Backup Command Execution#
Database backups in Dokploy follow the same generate bash string → execute locally or remotely pattern used throughout the codebase. The entire backup pipeline lives in packages/server/src/utils/backups/ .
Core Functions in utils.ts#
All backup shell script generation is centralized in packages/server/src/utils/backups/utils.ts.
Per-engine dump command builders — each returns a docker exec command string that passes credentials via -e VAR=<escaped> (using shell-quote) and references them as $VAR inside the inner shell, so credentials never appear in the command text :
| Function | Engine | Dump tool |
|---|---|---|
getPostgresBackupCommand | PostgreSQL | pg_dump -Fc piped through gzip |
getMariadbBackupCommand | MariaDB | mariadb-dump --single-transaction piped through gzip |
getMysqlBackupCommand | MySQL | mysqldump --single-transaction piped through gzip |
getMongoBackupCommand | MongoDB | mongodump --archive --gzip |
getLibsqlBackupCommand | LibSQL | `tar cf - |
All docker exec commands use set -o pipefail inside the inner shell so a failed dump doesn't silently produce a corrupt empty archive .
generateBackupCommand dispatches to the per-engine builders based on backup.databaseType and backup.backupType ("database" or "compose"). For compose backups it reads credentials from backup.metadata rather than a directly attached service record.
getContainerSearchCommand constructs the docker ps filter command used to discover the running container ID at runtime:
- Database services: filters on
com.docker.swarm.service.name - Compose stacks: filters on both
com.docker.stack.namespaceandcom.docker.swarm.service.name - Compose
docker-composeprojects: filters oncom.docker.compose.project
getS3Credentials assembles the rclone flag list from the destination record, using shell-quote for all user-controlled values.
getBackupCommand — Full Script Assembly#
getBackupCommand(backup, rcloneCommand, logPath) stitches the pieces into a complete bash script returned as a string. The script:
- Sets
set -eo pipefail - Resolves the container ID:
CONTAINER_ID=$(${containerSearch})and exits if empty - First backup invocation — runs the dump command with output discarded to probe for errors
- Second backup invocation — runs the same dump command again, piped to
rclone rcatfor upload
⚠️ Known Issue: Duplicate Dump Execution#
The backup command is executed twice per backup job. Lines 292 and 302 of utils.ts both interpolate and run ${backupCommand} :
# Step 3 — probe run, output discarded
BACKUP_OUTPUT=$(${backupCommand} 2>&1 >/dev/null) || { … exit 1; }
# Step 4 — actual upload run
UPLOAD_OUTPUT=$(${backupCommand} | ${rcloneCommand} 2>&1 >/dev/null) || { … exit 1; }
The probe run (step 3) discards all output, so the uploaded backup is always produced by the second run. The first run is waste.
Reported impact on a 9.4 GB PostgreSQL database :
- 2× wall clock time (16m31s vs ~8m)
- 2× CPU and disk I/O (
pg_dump -Fcpinned a core at 84% for twice as long) - 2×
ACCESS SHARElock window on all tables — doubles the period during which concurrentALTER TABLE/ migrations are blocked - Tracked in GitHub Issue #4915
Proposed fix: Use bash PIPESTATUS to detect dump-vs-upload failures in a single piped invocation, eliminating the probe run entirely :
set -o pipefail
OUTPUT=$(${backupCommand} | ${rcloneCommand} 2>&1 >/dev/null)
STATUS=("${PIPESTATUS[@]}")
# STATUS[0] → dump exit code, STATUS[1] → rclone exit code
Execution Dispatch#
Each per-engine runner (runPostgresBackup, runMySqlBackup, etc.) calls getBackupCommand, then dispatches based on the database's serverId :
const backupCommand = getBackupCommand(backup, rcloneCommand, deployment.logPath);
if (postgres.serverId) {
await execAsyncRemote(postgres.serverId, backupCommand);
} else {
await execAsync(backupCommand, { shell: "/bin/bash" });
}
This mirrors the same local/remote dispatch pattern used in deployment operations . After the backup, scheduleBackup calls keepLatestNBackups to prune old backup files from S3 via rclone delete .
Key Files#
| File | Role |
|---|---|
utils/backups/utils.ts | Central script assembly: getBackupCommand, generateBackupCommand, per-engine dump builders, getS3Credentials |
utils/backups/postgres.ts | runPostgresBackup — caller and executor |
utils/backups/mysql.ts | runMySqlBackup |
utils/backups/mariadb.ts | runMariadbBackup |
utils/backups/mongo.ts | runMongoBackup |
utils/backups/libsql.ts | runLibsqlBackup |
utils/backups/compose.ts | runComposeBackup |
utils/process/execAsync.ts | execAsync / execAsyncRemote execution layer |