# Email alerts (SMTP) Source: https://docs.dbdock.xyz/alerts/email Send backup notifications via any SMTP provider. DBDock sends email via standard SMTP — any provider works. ## Configuration ### `dbdock.config.json` ```json theme={null} { "alerts": { "email": { "enabled": true, "smtp": { "host": "smtp.gmail.com", "port": 587, "secure": false }, "from": "backups@yourapp.com", "to": ["admin@yourapp.com", "devops@yourapp.com"] } } } ``` ### `.env` ```bash theme={null} DBDOCK_SMTP_USER=your-smtp-username DBDOCK_SMTP_PASS=your-smtp-password ``` Multiple `to` addresses are supported — all recipients get every alert. ## Provider setup ```json theme={null} "smtp": { "host": "smtp.gmail.com", "port": 587, "secure": false } ``` ```bash theme={null} DBDOCK_SMTP_USER=your-email@gmail.com DBDOCK_SMTP_PASS=your-app-password ``` **Important:** Gmail requires an [App Password](https://support.google.com/accounts/answer/185833), not your regular account password. Enable 2FA first, then generate an App Password for "Mail". ```json theme={null} "smtp": { "host": "smtp.sendgrid.net", "port": 587, "secure": false } ``` ```bash theme={null} DBDOCK_SMTP_USER=apikey DBDOCK_SMTP_PASS=YOUR_SENDGRID_API_KEY ``` The username is literally the word `apikey` — not your SendGrid username. The password is the API key. ```json theme={null} "smtp": { "host": "email-smtp.us-east-1.amazonaws.com", "port": 587, "secure": false } ``` ```bash theme={null} DBDOCK_SMTP_USER=YOUR_SMTP_USERNAME DBDOCK_SMTP_PASS=YOUR_SMTP_PASSWORD ``` SES SMTP credentials are distinct from your AWS access keys. Generate them from the SES console → SMTP Settings. Replace `us-east-1` with your SES region. ```json theme={null} "smtp": { "host": "smtp.mailgun.org", "port": 587, "secure": false } ``` ```bash theme={null} DBDOCK_SMTP_USER=postmaster@your-domain.mailgun.org DBDOCK_SMTP_PASS=YOUR_MAILGUN_SMTP_PASSWORD ``` ```json theme={null} "smtp": { "host": "smtp.postmarkapp.com", "port": 587, "secure": false } ``` ```bash theme={null} DBDOCK_SMTP_USER=YOUR_POSTMARK_SERVER_TOKEN DBDOCK_SMTP_PASS=YOUR_POSTMARK_SERVER_TOKEN ``` Username and password are the same — both your server token. Any SMTP server works: ```json theme={null} "smtp": { "host": "mail.example.com", "port": 587, "secure": false } ``` Use `secure: true` + `port: 465` for implicit TLS. Use `secure: false` + `port: 587` for STARTTLS (most modern servers). ## Email content ### Success **Subject:** `✓ Backup complete — myapp (45.2 MB)` **Body:** backup ID, database, size, duration, storage path, encryption status. ### Failure **Subject:** `✗ Backup failed — myapp` **Body:** error message, timestamp, troubleshooting suggestion. ## Testing ```bash theme={null} npx dbdock test ``` Sends a test email to all `to` addresses. Check spam folders if it doesn't arrive. ## Common issues * Wrong username/password * Gmail: not using an App Password * Provider requires API key, not account password (SendGrid, Postmark) * Port blocked by network firewall * Try port 465 with `secure: true` instead of 587 * Check spam folder * Verify `from` address is allowed by the provider (SendGrid/SES require domain verification) * Check provider's send logs (SendGrid activity feed, SES CloudWatch) ## Security * SMTP credentials live in `.env`, never in `dbdock.config.json` * DBDock uses STARTTLS when `secure: false` + port 587 * If your SMTP server requires a certificate chain outside the Node defaults, you'll need to set `NODE_EXTRA_CA_CERTS` ## See also Real-time Slack notifications. Discord, WhatsApp, and custom endpoints. # Alerts overview Source: https://docs.dbdock.xyz/alerts/overview Get notified when backups succeed or fail. DBDock can send notifications when a backup completes (success or failure). Alerts work for both CLI backups and programmatic backups — the system reads from the same `alerts` config in either mode. ## Channels SMTP via Gmail, SendGrid, AWS SES, Mailgun, or any provider. Incoming webhooks — 2-minute setup. Any HTTP endpoint — Discord, WhatsApp, your own service. Run backups on a cron schedule. ## When alerts fire Every completed backup triggers an alert, whether it succeeded or failed. ### On success Alert includes: * Backup ID * Database name * Size (original and compressed) * Duration * Storage location * Encryption status ### On failure Alert includes: * Error message * Database details * Timestamp * Troubleshooting tip (based on the error) ## Configuration All alerts are configured in `dbdock.config.json`: ```json theme={null} { "alerts": { "email": { "enabled": true, "smtp": { "host": "...", "port": 587, "secure": false }, "from": "backups@yourapp.com", "to": ["admin@yourapp.com"] }, "slack": { "enabled": true, "webhookUrl": "https://hooks.slack.com/services/..." } } } ``` Secrets (SMTP password, Slack webhook URL) go in `.env`: ```bash theme={null} DBDOCK_SMTP_USER=your-smtp-user DBDOCK_SMTP_PASS=your-smtp-password DBDOCK_SLACK_WEBHOOK=https://hooks.slack.com/services/... ``` ## Testing alerts ```bash theme={null} npx dbdock test ``` Sends a test notification to each enabled channel without creating a backup. ## Delivery behavior Alerts are sent **asynchronously** — they never block backup completion. If an alert delivery fails, the backup still succeeds and the failure is logged. ## Best practices * **Route failures to an on-call channel.** Successes are nice-to-have; failures need eyes on them fast. * **Don't wire backups into a noisy channel.** A 100-person #general gets ignored. * **Use email for batch reports, Slack for real-time.** Set email for weekly summaries, Slack for immediate failures. * **Test after setup.** Run `dbdock test` to confirm delivery before trusting the alerts. ## See also Configure SMTP. 2-minute webhook setup. # Scheduling backups Source: https://docs.dbdock.xyz/alerts/scheduling Run automated backups on a cron schedule. DBDock supports three ways to run scheduled backups. Pick based on your deployment. Simplest. A crontab entry runs `dbdock backup` on a schedule. Long-lived Node.js process using `node-cron`. Kubernetes CronJob, AWS EventBridge, GCP Cloud Scheduler. ## Option 1 — System cron (recommended for single server) Add a crontab entry: ```bash theme={null} crontab -e ``` ``` 0 2 * * * cd /app && npx dbdock backup >> /var/log/dbdock.log 2>&1 ``` This runs a backup at 02:00 every day. Adjust the path, time, and log file. ### Pros * Simplest possible setup * Battle-tested scheduler * Works even if DBDock isn't running ### Cons * Limited logging/observability * No programmatic control * Harder on Kubernetes/serverless ## Option 2 — Programmatic with node-cron Run DBDock as a long-lived Node.js process. Useful when you want to share backup scheduling with the rest of your app. ```bash theme={null} npm install node-cron ``` ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); const cron = require('node-cron'); async function main() { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); cron.schedule('0 2 * * *', async () => { try { const result = await backups.createBackup({ compress: true, encrypt: true, }); console.log(`Backup ${result.metadata.id} completed`); } catch (err) { console.error('Backup failed', err); } }); console.log('Scheduler started'); } main(); ``` Keep the process alive with PM2, systemd, or Docker. See [SDK → scheduling](/sdk/scheduling) for more detail. ### Pros * Full control — custom logic before/after backup * Tight integration with app observability * Works with alert programmatic API ### Cons * Needs a long-lived process * One more thing that can crash ## Option 3 — Cloud schedulers ### Kubernetes CronJob ```yaml theme={null} apiVersion: batch/v1 kind: CronJob metadata: name: dbdock-backup spec: schedule: "0 2 * * *" jobTemplate: spec: template: spec: containers: - name: dbdock image: node:20-alpine command: ["npx", "dbdock", "backup"] envFrom: - secretRef: name: dbdock-secrets restartPolicy: OnFailure ``` ### AWS EventBridge + Fargate/Lambda Schedule rule → ECS RunTask (Fargate) that runs a DBDock container. Or package as a Lambda if your backup fits in 15 minutes and 10 GB. ### GCP Cloud Scheduler + Cloud Run Cloud Scheduler → HTTPS → Cloud Run service that invokes `dbdock backup`. ### Pros * Fully managed, scales with your infra * Rich logging and retry semantics * Runs even if your app is down ### Cons * More moving pieces * Infrastructure-specific setup ## Using the `dbdock schedule` command The `dbdock schedule` command stores schedules in `dbdock.config.json`: ```json theme={null} { "schedules": [ { "name": "daily", "cron": "0 2 * * *", "enabled": true } ] } ``` These are **not executed by the CLI alone** — they're config entries. To execute them, use the programmatic approach above, which reads the schedules from the config file automatically. If you're using system cron or cloud schedulers, skip `dbdock schedule` — your scheduler of choice holds the schedule. ## Recommended schedule patterns | Frequency | Cron | Use case | | ------------- | ------------- | ------------------------------- | | Every 6 hours | `0 */6 * * *` | High-churn production databases | | Daily at 2 AM | `0 2 * * *` | Most production setups | | Weekly | `0 0 * * 0` | Archival + weekly snapshots | | Monthly | `0 0 1 * *` | Compliance retention | Pair a frequent schedule with a retention policy to keep storage under control — see [Retention strategies](/guides/retention-strategies). ## See also Manage schedules via CLI. Programmatic scheduling details. # Slack alerts Source: https://docs.dbdock.xyz/alerts/slack Send backup notifications to Slack via incoming webhooks. Slack alerts use [incoming webhooks](https://api.slack.com/messaging/webhooks) — the simplest Slack integration. No app installation required for the user side; just a webhook URL. ## Setup Go to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App → From scratch**. Name it "DBDock" (or whatever you like) and pick your workspace. In the app settings, go to **Incoming Webhooks** and toggle it on. Click **Add New Webhook to Workspace**. Pick the channel where alerts should post (e.g. `#backups` or `#ops-alerts`). Slack generates a webhook URL. The URL looks like `https://hooks.slack.com/services/T.../B.../...`. Copy it. ## Configuration ### `dbdock.config.json` ```json theme={null} { "alerts": { "slack": { "enabled": true } } } ``` ### `.env` ```bash theme={null} DBDOCK_SLACK_WEBHOOK=https://hooks.slack.com/services/T.../B.../... ``` Alternatively, set the webhook in the config (less recommended): ```json theme={null} { "alerts": { "slack": { "enabled": true, "webhookUrl": "https://hooks.slack.com/services/T.../B.../..." } } } ``` The `.env` approach is preferred — keeps the URL out of version control. ## Message format Slack messages look like: **✓ Backup complete** Database: `myapp` Size: 45.2 MB (compressed) Duration: 8.4s Storage: `s3://my-backups/dbdock_backups/backup-...sql` **✗ Backup failed** Database: `myapp` Error: Connection timeout Timestamp: 2026-04-16 08:00:02 Tip: Check database is reachable from the runner ## Testing ```bash theme={null} npx dbdock test ``` Sends a test message to the channel. Verify it arrives and looks right. ## Routing ### Alerting strategy * `#backups` — all events (success + failure) * `#ops-alerts` — failures only (separate webhook, separate app instance) DBDock supports one webhook per environment. For multiple channels, run separate DBDock configs (dev, staging, prod) with different webhook URLs. ### Channel permissions The webhook can only post to the channel it was created for. To change channels, create a new webhook and update `DBDOCK_SLACK_WEBHOOK`. ## Common issues Webhook URL is correct but Slack rejected the message. Usually a transient issue — retry. The channel was deleted, or the webhook was revoked. Recreate the webhook. If you see raw JSON or unformatted text, your Slack workspace may have legacy incoming webhooks (pre-2019). Recreate the app from scratch. ## Security * The webhook URL is a secret — anyone with it can post to the channel * Store it in `.env`, never commit it * Rotate webhooks periodically (Slack dashboard → Incoming Webhooks → regenerate) * If accidentally committed, [revoke](https://api.slack.com/apps) it immediately ## See also SMTP-based alerts. Discord, Teams, and custom endpoints. # Custom webhooks Source: https://docs.dbdock.xyz/alerts/webhooks Send alerts to Discord, Teams, WhatsApp, or any HTTP endpoint. DBDock can POST alerts to any HTTP endpoint. This opens the door to Discord, Microsoft Teams, WhatsApp via third-party bridges, and your own internal services. ## Configuration ```bash theme={null} DBDOCK_CUSTOM_WEBHOOK=https://your-service.example.com/api/hooks/dbdock ``` DBDock POSTs a JSON payload to that URL on every backup event. ## Payload shape ### Success ```json theme={null} { "event": "backup.success", "timestamp": "2026-04-16T08:00:08.432Z", "database": "myapp", "backup": { "id": "backup-2026-04-16-08-00-00-abc123", "size": 47392028, "compressedSize": 12056312, "duration": 8432, "encrypted": true, "compressed": true, "storageKey": "s3://my-backups/dbdock_backups/backup-...sql" } } ``` ### Failure ```json theme={null} { "event": "backup.failure", "timestamp": "2026-04-16T08:00:02.100Z", "database": "myapp", "error": { "message": "Connection timeout", "code": "ETIMEDOUT", "stack": "..." } } ``` ## Discord Discord accepts Slack-formatted payloads at its webhook URL with `/slack` appended: ``` https://discord.com/api/webhooks///slack ``` Set that as your `DBDOCK_SLACK_WEBHOOK` (not the custom webhook) — DBDock's Slack alerts format correctly for Discord. For richer Discord messages, use the custom webhook and write your own translator service. ## Microsoft Teams Teams incoming webhook URLs accept Slack-like payloads via the [Workflows app](https://support.microsoft.com/en-us/office/create-incoming-webhooks-with-workflows-for-microsoft-teams-8ae491c7-0394-4861-ba59-055e33f75498). If you're using the Workflows approach, create a flow "When a Teams webhook request is received" and point `DBDOCK_CUSTOM_WEBHOOK` at its URL. ## WhatsApp WhatsApp doesn't have official webhooks. You'll need a bridge service: * **Twilio WhatsApp API** — POST from your own service that wraps Twilio * **WhatsApp Business API providers** — 360dialog, Gupshup, etc. Point `DBDOCK_CUSTOM_WEBHOOK` at your bridge service, which then forwards to WhatsApp. ## Writing your own bridge A minimal Node.js bridge that receives DBDock alerts and forwards them: ```javascript theme={null} const express = require('express'); const app = express(); app.use(express.json()); app.post('/hooks/dbdock', async (req, res) => { const { event, database, backup, error } = req.body; if (event === 'backup.success') { await sendToMyService(`✓ ${database} backup complete (${backup.id})`); } else if (event === 'backup.failure') { await sendToMyService(`✗ ${database} backup failed: ${error.message}`); } res.status(200).send('ok'); }); app.listen(3000); ``` Deploy anywhere (Cloud Run, Lambda, your own server) and set `DBDOCK_CUSTOM_WEBHOOK` to its URL. ## Delivery behavior * POST with `Content-Type: application/json` * 10-second timeout * No retries — if your endpoint is down, the alert is lost (DBDock logs the error) * Alert delivery does not block backup completion ## Security * The webhook URL is a secret if your endpoint doesn't have its own auth * For sensitive deployments, add a shared secret in your endpoint URL or as a query param: ``` DBDOCK_CUSTOM_WEBHOOK=https://api.example.com/hooks?token=shared-secret ``` * Then validate `token` in your service. ## See also Built-in Slack support. SMTP notifications. # dbdock account Source: https://docs.dbdock.xyz/cli/account Show your DBDock plan and the limits that apply to your account — connections, backups, schedules, storage, alerts, and team size. ```bash theme={null} npx dbdock account [options] ``` Prints your current plan and the limits that come with it. Handy for checking what you're entitled to before configuring schedules, storage, or alerts. Requires a signed-in account ([`dbdock login`](/cli/login)). ## Quick example ```bash theme={null} dbdock account ``` ``` Account: you@example.com Plan: pro Limits: Connections: unlimited Backups / month: unlimited Schedules: unlimited Encrypted backups: yes Managed storage: 50 GB Alerts: unlimited Alert channels: email, slack, webhook Team members: 5 ``` ## Options | Option | Description | | ------------------ | ------------------------------------------------------ | | `--profile ` | Use a specific saved profile instead of the active one | ## See also Managed storage usage and quota. Manage cloud alert channels and rules. # dbdock alert Source: https://docs.dbdock.xyz/cli/alert Manage DBDock Cloud notification channels and alert rules from the CLI — the same alerts you'd configure in the dashboard. ```bash theme={null} npx dbdock alert [action] [options] ``` Manages the cloud notification channels and alert rules on your account — the same ones you'd set up in the dashboard. Requires a signed-in account ([`dbdock login`](/cli/login)). Channel types and rule counts depend on your plan; see [`dbdock account`](/cli/account). ## Actions | Action | What it does | | ---------------- | ----------------------------------------------------- | | `list` (default) | List your channels and alert rules | | `add` | Add a notification channel (email, Slack, or webhook) | | `rule` | Add an alert rule that notifies a channel on an event | | `test` | Send a test notification to a channel | | `remove` | Remove a channel or rule | ## Quick examples ```bash theme={null} dbdock alert # list channels and rules dbdock alert add # add a channel (interactive) dbdock alert rule # notify a channel on backup failure dbdock alert test # send a test to a channel dbdock alert remove # remove a channel or rule ``` ``` Notification channels: Ops Slack [slack] 6f2c... Alert rules: Nightly failures on backup_failure → Ops Slack ``` ## Events Alert rules can trigger on: * `backup_success` — a backup completed * `backup_failure` — a backup failed * `schedule_missed` — a schedule didn't run on time * `storage_error` — a storage upload or download failed ## Options | Option | Description | | ------------------ | ------------------------------------------------------ | | `--profile ` | Use a specific saved profile instead of the active one | `add`, `rule`, `test`, and `remove` are interactive and need a terminal (TTY). ## See also How DBDock alerting works. Which channels your plan allows. # dbdock backup Source: https://docs.dbdock.xyz/cli/backup Create a database backup with compression and encryption. ```bash theme={null} npx dbdock backup [options] ``` Runs `pg_dump`, optionally compresses and encrypts the output, and streams it directly to your configured storage provider. You'll see real-time progress: ``` ████████████████████ | 100% | 45.23/100 MB | Speed: 12.50 MB/s | ETA: 0s | Uploading to S3 ✔ Backup completed successfully ``` ## Options | Option | Description | | ---------------------------- | ---------------------------------------------- | | `--encrypt` | Force encryption on (overrides config) | | `--no-encrypt` | Force encryption off (overrides config) | | `--compress` | Force compression on (overrides config) | | `--no-compress` | Force compression off (overrides config) | | `--encryption-key ` | Use a specific 64-char hex key for this backup | | `--compression-level <1-11>` | zstd compression level (default `6`) | ## Examples ### Standard backup Uses everything from your config file: ```bash theme={null} npx dbdock backup ``` ### Force maximum compression ```bash theme={null} npx dbdock backup --compress --compression-level 11 ``` Useful for archival backups where you'll keep them for months. ### Fast backup, no compression ```bash theme={null} npx dbdock backup --no-compress ``` When your storage is cheap and restore speed matters more than size. ### One-off with explicit encryption key ```bash theme={null} npx dbdock backup --encrypt --encryption-key "$(cat ~/.keys/dbdock.key)" ``` Overrides `DBDOCK_ENCRYPTION_SECRET` just for this run. ## Backup formats The format comes from `dbdock.config.json`: ```json theme={null} { "backup": { "format": "custom" } } ``` | Format | Extension | Notes | | ------------------ | --------- | -------------------------------------------------------- | | `custom` (default) | `.sql` | Binary, pg\_dump's native compression, selective restore | | `plain` | `.sql` | Human-readable SQL, works with `psql` directly | | `directory` | `.dir` | Parallel dump support for huge DBs | | `tar` | `.tar` | Tar archive of directory format | See [Concepts → backup formats](/core/concepts#backup-formats) for when to pick which. ## What happens under the hood 1. **Connect** — validates database credentials 2. **Dump** — runs `pg_dump` with your configured format 3. **Compress** (if enabled) — zstd at configured level 4. **Encrypt** (if enabled) — AES-256-GCM with key derived from secret 5. **Upload** — streams to your storage provider, no temp files 6. **Record metadata** — size, duration, flags, storage key 7. **Send alerts** (if configured) — Slack/email 8. **Retention** (if `runAfterBackup: true`) — cleanup old backups ## After the backup ```bash theme={null} npx dbdock list # See it in the list npx dbdock restore # Restore to verify ``` ## Generating an encryption key ```bash theme={null} node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` Store the output in `.env` as `DBDOCK_ENCRYPTION_SECRET`. See [Security](/security/overview) for key management. # dbdock cleanup Source: https://docs.dbdock.xyz/cli/cleanup Apply your retention policy to remove old backups. ```bash theme={null} npx dbdock cleanup [options] ``` `cleanup` applies the `retention` policy from `dbdock.config.json`. It's automatic (when `runAfterBackup: true`) and manual (via this command). ## Options | Option | Description | | ----------- | ---------------------------------------------- | | `--dry-run` | Preview what would be deleted without deleting | | `--force` | Skip the confirmation prompt | ## Interactive preview (default) ```bash theme={null} npx dbdock cleanup ``` ``` Retention policy: • maxBackups: 100 • maxAgeDays: 30 • minBackups: 5 Analyzing backups... Will delete 12 backup(s), reclaiming 542.1 MB: • backup-2025-10-01-... (45.2 MB) — 197 days old • backup-2025-10-02-... (45.1 MB) — 196 days old ... ? Proceed? (y/N) ``` ## Dry run See what would happen without doing it: ```bash theme={null} npx dbdock cleanup --dry-run ``` Exits with code `0` if there's nothing to delete, so it's safe in CI. ## Force (no prompt) For automated cleanup in cron jobs: ```bash theme={null} npx dbdock cleanup --force ``` Combined with cron: ``` 0 3 * * 0 npx dbdock cleanup --force # Weekly on Sunday at 3am ``` ## Retention policy Defined in `dbdock.config.json`: ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 100, "maxAgeDays": 30, "minBackups": 5, "runAfterBackup": true } } } ``` | Field | Description | | ---------------- | --------------------------------------------------------------------------- | | `maxBackups` | Keep at most N backups. Oldest deleted first. | | `maxAgeDays` | Delete anything older than N days. | | `minBackups` | **Safety net** — never delete below this count, even if other rules say so. | | `runAfterBackup` | Run cleanup automatically after each `dbdock backup`. | ### How the rules combine 1. Start with all backups 2. Sort by age, newest first 3. The most recent `minBackups` are untouchable 4. Of the rest, delete anything exceeding `maxBackups` or older than `maxAgeDays` `minBackups` always wins. If you have 3 backups and `minBackups: 5`, cleanup deletes nothing. ## Strategies See [Retention strategies](/guides/retention-strategies) for common policies (daily/weekly/monthly rotations, archival rules, etc.). # dbdock copydb Source: https://docs.dbdock.xyz/cli/copydb Copy a PostgreSQL database between two URLs — no config, no backup file. ```bash theme={null} npx dbdock copydb [options] ``` `copydb` is the "I just need to move this database" command. No config file. No intermediate backup file. Just paste two URLs and go. ## Quick example ```bash theme={null} npx dbdock copydb \ "postgresql://user:pass@prod.example.com:5432/myapp" \ "postgresql://user:pass@staging.example.com:5432/myapp" ``` ## What it does 1. Tests both connections 2. Shows source database size and table count 3. Warns if the target has existing data 4. Asks for confirmation 5. Streams `pg_dump` directly into `pg_restore` — no temp files, no waiting ## Options | Option | Description | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `--schema-only` | Copy tables, indexes, constraints — no data | | `--data-only` | Copy data only (schema must already exist on target) | | `--verbose` | Show detailed pg\_dump/pg\_restore output | | `--driver` | Use direct PostgreSQL driver instead of `pg_dump`. Required for serverless/modified Postgres (Neon, Supabase pooler, PlanetScale Postgres, etc.) | ## Common use cases ### Refresh staging from production ```bash theme={null} npx dbdock copydb "$PROD_URL" "$STAGING_URL" ``` ### Promote staging to production ```bash theme={null} npx dbdock copydb "$STAGING_URL" "$PROD_URL" ``` ### Pull production down to local for debugging ```bash theme={null} npx dbdock copydb "$PROD_URL" "postgresql://postgres:pass@localhost:5432/myapp" ``` ### Align schema across environments ```bash theme={null} npx dbdock copydb --schema-only "$PROD_URL" "$STAGING_URL" ``` ## The `--driver` flag Some serverless Postgres services (Neon, Supabase pooler, and others that use modified Postgres) reject `pg_dump` because it requires specific superuser operations or exact version matches. If you hit errors like: ``` pg_dump: error: server version: 15.3; pg_dump version: 14.9 ``` or ``` pg_dump: error: could not connect to server ``` ...use the `--driver` flag to use DBDock's direct Postgres client instead: ```bash theme={null} npx dbdock copydb --driver "$NEON_URL" "$LOCAL_URL" ``` The driver mode does not support all `pg_dump` features (e.g., function/procedure bodies for non-PL/pgSQL languages). Use `pg_dump` mode when possible. ## Safety `copydb` refuses to proceed silently when the target database has data. You'll see a confirmation prompt listing target size and table count before anything writes. If you're scripting this in CI, wrap it with an explicit empty target: ```bash theme={null} psql "$TARGET_URL" -c "DROP DATABASE IF EXISTS myapp; CREATE DATABASE myapp;" npx dbdock copydb "$SOURCE_URL" "$TARGET_URL" ``` ## See also End-to-end workflow for syncing environments. Moving between MongoDB and Postgres. # dbdock delete Source: https://docs.dbdock.xyz/cli/delete Delete specific backups or all backups. ```bash theme={null} npx dbdock delete [options] ``` ## Modes Default mode — DBDock shows a picker. ```bash theme={null} npx dbdock delete ``` Delete a specific backup by its ID. ```bash theme={null} npx dbdock delete --key backup-2026-04-16-08-00-00-abc123 ``` Delete every backup. Requires confirmation. ```bash theme={null} npx dbdock delete --all ``` This is destructive and cannot be undone. DBDock will ask you to type the database name to confirm. ## Options | Option | Description | | ------------ | ------------------------------------------- | | `--key ` | Delete a specific backup by ID | | `--all` | Delete every backup (requires confirmation) | ## Difference from `cleanup` `delete` is manual and ad-hoc. `cleanup` applies the retention policy defined in your config. * You want to remove specific bad/test backups * You're decommissioning a project * You need to nuke everything immediately * You want automatic retention * You want to apply `maxBackups` / `maxAgeDays` rules * You want a dry run first ## Safety * Interactive mode always shows what will be deleted before confirmation * `--all` requires typing the database name as confirmation * Deletes happen one at a time with logging — if one fails, the rest continue # dbdock init Source: https://docs.dbdock.xyz/cli/init Interactive setup wizard — run once per project. ```bash theme={null} npx dbdock init ``` `init` creates your initial configuration. It's interactive — DBDock asks questions, you answer, and it generates the right files. ## What it asks 1. **Database connection** — host, port, user, database name 2. **Storage provider** — DBDock Storage (managed, recommended), local, S3, R2, or Cloudinary 3. **Storage credentials** (for your own cloud buckets; DBDock Storage needs none) 4. **Encryption** — enable/disable, generates a key if yes 5. **Compression** — enable/disable, compression level 6. **Alerts** — optional email (SMTP) and Slack setup ## What it creates Two files: Non-sensitive configuration. Commit this. Secrets. **Never commit.** Automatically added to `.gitignore`. It also updates `.gitignore` to include `.env`, `backups/`, and `*.backup`. ## Environment-only setup If you prefer to skip the config file entirely, you can configure DBDock via environment variables alone. Set these in `.env`: ```bash theme={null} DBDOCK_DB_URL=postgresql://user:pass@host:5432/db STORAGE_PROVIDER=s3 STORAGE_BUCKET=my-backups DBDOCK_STORAGE_ACCESS_KEY=... DBDOCK_STORAGE_SECRET_KEY=... ``` See the [Configuration reference](/core/configuration) for the full list. ## Re-running init Running `init` again in a directory that already has a config file will ask whether to overwrite it. Existing values become defaults in the prompts, so you only need to change what you want to change. ## After init Run `dbdock test` to validate everything. Run `dbdock backup` to create your first backup. # dbdock list Source: https://docs.dbdock.xyz/cli/list List all available backups with filtering. ```bash theme={null} npx dbdock list [options] ``` Shows backups from your configured storage provider. When you have more than 50 backups, DBDock auto-filters to keep the output readable. ## Options | Option | Description | | -------------------- | --------------------------------- | | `--recent ` | Show the N most recent backups | | `--search ` | Filter by keyword in backup ID | | `--days ` | Show backups from the last N days | | `--limit ` | Limit total results | ## Examples ### Most recent ```bash theme={null} npx dbdock list --recent 10 ``` ### Last week ```bash theme={null} npx dbdock list --days 7 ``` ### Search by keyword ```bash theme={null} npx dbdock list --search "pre-deploy" ``` Matches any backup whose ID contains "pre-deploy". ### Combine filters ```bash theme={null} npx dbdock list --days 30 --limit 20 ``` Last 30 days, capped at 20 results. ## Output ``` ┌────────────────────────────────────┬──────────┬───────────┬─────────────────────┐ │ ID │ Size │ Encrypted │ Created │ ├────────────────────────────────────┼──────────┼───────────┼─────────────────────┤ │ backup-2026-04-16-08-00-00-abc123 │ 45.2 MB │ ✓ │ 2026-04-16 08:00:00 │ │ backup-2026-04-15-08-00-00-def456 │ 45.1 MB │ ✓ │ 2026-04-15 08:00:00 │ │ backup-2026-04-14-08-00-00-ghi789 │ 44.8 MB │ ✓ │ 2026-04-14 08:00:00 │ └────────────────────────────────────┴──────────┴───────────┴─────────────────────┘ Total: 3 backup(s) — 135.1 MB ``` ## Scripting The command writes human-readable output by default. For scripting, use the [SDK](/sdk/listing-backups) which returns structured data. # dbdock login Source: https://docs.dbdock.xyz/cli/login Sign in to DBDock Cloud from the CLI with browser OAuth. Includes logout, whoami, and switch-org, plus token-based sign-in for CI and profiles for multiple accounts. ```bash theme={null} npx dbdock login [options] ``` Signs you in to DBDock Cloud so the CLI can [sync this project](/cli/sync) to your dashboard. Sign-in uses browser **OAuth** — there's no API key to create. For the full walkthrough, see [Authentication](/cloud-sync/authentication). ## Quick example ```bash theme={null} dbdock login # Opens your browser to authorize the CLI # → Logged in as you@example.com (profile: default) ``` If the browser doesn't open, the CLI prints a URL to visit manually. Credentials are stored under `~/.dbdock/` — not in your project. ## Options | Option | Description | | ------------------ | ----------------------------------------------------------------------------------------- | | `--token ` | Sign in with a token instead of the browser flow (for CI). Also read from `DBDOCK_TOKEN`. | | `--web` | Sign in via the browser (the default). | | `--profile ` | Sign in to a named account profile. | ## Related account commands Show the currently authenticated account — email, id, auth method, org, and active profile. ```bash theme={null} dbdock whoami ``` Remove stored credentials for the active profile. Your project link is left intact. ```bash theme={null} dbdock logout [--profile ] ``` Set the active organization. Forward-compatible — accounts are single-scope today. ```bash theme={null} dbdock switch-org --org ``` ## CI usage ```bash theme={null} export DBDOCK_TOKEN="..." # from your CI secret store dbdock login # picks up the token automatically dbdock sync ``` Never commit a token. Inject `DBDOCK_TOKEN` from your CI provider's secret store. See [Key management](/security/key-management). ## Profiles Work with more than one account by naming profiles. Each keeps its own credentials and endpoint. ```bash theme={null} dbdock login --profile work dbdock sync # uses default unless you pass --profile work ``` ## Next Signed in — now push this project to the cloud. # dbdock migrate-config Source: https://docs.dbdock.xyz/cli/migrate-config Move legacy secrets from the config file to environment variables. ```bash theme={null} npx dbdock migrate-config ``` Older versions of DBDock (pre-1.1) stored secrets directly in `dbdock.config.json`. `migrate-config` extracts them and moves them to `.env`, which is where they should be. ## When to run it If you have any of the following in `dbdock.config.json`: * `database.password` * `storage.s3.accessKeyId` / `secretAccessKey` * `storage.cloudinary.apiKey` / `apiSecret` * `backup.encryption.secret` * `alerts.email.smtp.auth.user` / `pass` * `alerts.slack.webhookUrl` Run this command once — it's a one-shot cleanup. ## What it does 1. **Reads** `dbdock.config.json` 2. **Extracts** secrets to `.env` (appending, not overwriting existing vars) 3. **Rewrites** `dbdock.config.json` without the secrets 4. **Updates** `.gitignore` to ensure `.env` is excluded 5. **Prints** a summary of what moved where ## Sample output ``` Analyzing dbdock.config.json... Found 4 secret(s) in config: • database.password • storage.s3.secretAccessKey • backup.encryption.secret • alerts.slack.webhookUrl Moving to .env: ✓ DBDOCK_DB_PASSWORD ✓ DBDOCK_STORAGE_SECRET_KEY ✓ DBDOCK_ENCRYPTION_SECRET ✓ DBDOCK_SLACK_WEBHOOK Updated: ✓ dbdock.config.json (secrets removed) ✓ .env (secrets added) ✓ .gitignore (.env entry added) Done. Review the changes and commit dbdock.config.json + .gitignore. Never commit .env. ``` ## Safe to run multiple times If there are no secrets in the config, `migrate-config` exits cleanly with no changes. You can run it anytime to check. ## After migration Enable strict mode to prevent regression: ```bash theme={null} echo 'DBDOCK_STRICT_MODE=true' >> .env ``` DBDock will then refuse to load any config file that still contains secrets. ## See also Why secrets don't belong in config files. Where every secret should live. # dbdock open Source: https://docs.dbdock.xyz/cli/open Open the linked DBDock project in the cloud dashboard from your terminal, or print the URL for use over SSH. ```bash theme={null} npx dbdock open [options] ``` Opens this project in the [DBDock Cloud](https://dbdock.xyz) dashboard in your browser. Useful right after a [`dbdock sync`](/cli/sync) to review what pushed. ## Options | Option | Description | | --------- | ------------------------------------------------------- | | `--print` | Print the dashboard URL instead of launching a browser. | ## Examples ```bash Open in browser theme={null} dbdock open # → Opening https://dbdock.xyz/... ``` ```bash Print the URL (e.g. over SSH) theme={null} dbdock open --print ``` `open` needs a linked project. If you see "No linked project," run [`dbdock init`](/cli/init) to link this directory first. ## Related Push before you open. What's in the dashboard. # CLI Overview Source: https://docs.dbdock.xyz/cli/overview Every DBDock CLI command at a glance — setup, backups, restores, database copies, cross-database migration, schedules, and Cloud Sync (login, sync, open). DBDock ships a single command — `dbdock` — with subcommands for setup, backups, restores, migration, scheduling, and syncing to [DBDock Cloud](/cloud/overview). It's open source (MIT) and runs anywhere Node.js does. Each command has its own page with options and examples. No install needed to try it: `npx dbdock `. To install globally, see [Installation](/get-started/installation). ## Command index ### Setup Interactive setup wizard. Run once per project — it can also link the project to DBDock Cloud. Move legacy secrets from the config file into environment variables. ### Backup lifecycle Create a backup with encryption and compression. Interactive restore with smart filtering. List all backups with filtering. Delete specific backups or all of them. Apply the retention policy. ### Direct database operations Copy a PostgreSQL database directly between two URLs. Cross-database migration, MongoDB ↔ PostgreSQL. Inspect a database's structure before migrating. ### Diagnostics & schedules Verify database, storage, and alert config. View configured schedules. Manage cron schedules. ### Cloud Sync Sign in to DBDock Cloud (also: `logout`, `whoami`, `switch-org`). Push local config to the cloud, check status, pull, resolve conflicts. Open the linked project in the dashboard. New to syncing the CLI with the dashboard? Start with the [Cloud Sync overview](/cloud-sync/overview). ## Global flags | Flag | Description | | ----------------- | ------------------------ | | `--help`, `-h` | Show command help | | `--version`, `-V` | Print the DBDock version | ## Exit codes | Code | Meaning | | ----- | ----------------------------------------- | | `0` | Success | | `1` | General error (including a sync conflict) | | `130` | Interrupted (Ctrl+C / SIGINT) | Commands that perform destructive actions confirm interactively unless you pass `--force` (where supported). ## Getting help * `dbdock --help` — command-specific help * [Troubleshooting](/help/troubleshooting) — common issues * [GitHub](https://github.com/dbdock/dbdock) — source and discussions # dbdock restore Source: https://docs.dbdock.xyz/cli/restore Interactive restore with smart filtering and migration support. ```bash theme={null} npx dbdock restore ``` DBDock lists available backups and lets you pick one. When you have 50+ backups, it auto-enables smart filtering so you don't scroll through walls of text. ## Interactive flow ``` ? Select a backup to restore: ❯ backup-2026-04-16-08-00-00-abc123 (45.2 MB) — 2 hours ago backup-2026-04-15-08-00-00-def456 (45.1 MB) — 1 day ago backup-2026-04-14-08-00-00-ghi789 (44.8 MB) — 2 days ago Show more... Filter by... ``` After picking: ``` Progress: ──────────────────────────────────────────────────────── ✔ Downloading backup ✔ Decrypting data ✔ Decompressing data ⟳ Restoring to database... ──────────────────────────────────────────────────────── ✔ All steps completed in 8.42s ``` ## Smart filtering When you have many backups, DBDock offers filtering options: * **Recent** — last 10 * **Date range** — 24h, 7d, 30d, 90d, or custom * **Search** — by keyword in the backup ID or by ID prefix Use `dbdock list` for non-interactive filtering. ## Restore destinations At the start of the restore flow, DBDock asks where to restore: Restore into the database configured in `dbdock.config.json`. Most common. Restore into a different database. Great for staging refreshes or recovery drills. ### Restoring to a different database 1. Select a backup 2. Pick "New Database Instance (Migrate)" 3. Enter target connection: host, port, user, password, database name 4. DBDock shows source stats and target database state, then asks for confirmation This is the same engine that powers `dbdock copydb` — see [Staging refresh guide](/guides/staging-refresh) for common workflows. ## What happens under the hood 1. **List** — fetches backup metadata from storage 2. **Download** — streams from storage (S3/R2/Cloudinary/local) 3. **Decrypt** (if encrypted) — AES-256-GCM using `DBDOCK_ENCRYPTION_SECRET` 4. **Decompress** (if compressed) — zstd 5. **Restore** — runs `pg_restore` (or `psql` for plain format) ## Gotchas ### Target database must exist DBDock doesn't create the target database for you. If the database doesn't exist: ```bash theme={null} psql -h host -p port -U user -c "CREATE DATABASE mydb;" ``` ### Target database should be empty (or you know what you're doing) `pg_restore` has `--clean` behavior which drops existing objects. For a completely clean restore, drop and recreate the target first. ### Encryption key Encrypted backups cannot be restored without the same `DBDOCK_ENCRYPTION_SECRET` that created them. If you're restoring to a new environment, copy the key first. ## Programmatic restore Restore is CLI-only at the moment. Programmatic restore is planned — follow [dbdock/dbdock#issues](https://github.com/dbdock/dbdock/issues) for updates. # dbdock schedule Source: https://docs.dbdock.xyz/cli/schedule Manage backup schedules stored in your config file. ```bash theme={null} dbdock schedule ``` `schedule` is an interactive menu for adding, editing, and removing cron schedules. Schedules are stored in `dbdock.config.json`. **The CLI manages config — it doesn't run schedules.** To actually execute scheduled backups, you need to either run DBDock as a long-lived process (see [scheduling guide](/alerts/scheduling)) or use an external scheduler like system cron. ## Interactive menu ``` ? What do you want to do? ❯ Add a schedule List schedules Enable/disable a schedule Delete a schedule Exit ``` ## Presets When adding a schedule, DBDock offers common presets: | Preset | Cron | Description | | ---------------- | ----------- | --------------------------------- | | Hourly | `0 * * * *` | Every hour on the hour | | Daily (midnight) | `0 0 * * *` | 00:00 every day | | Daily (2 AM) | `0 2 * * *` | 02:00 every day | | Weekly (Sunday) | `0 0 * * 0` | 00:00 every Sunday | | Monthly | `0 0 1 * *` | 00:00 on the 1st of each month | | Custom | your cron | Any valid 5-field cron expression | ## Schedule structure Schedules end up in `dbdock.config.json`: ```json theme={null} { "schedules": [ { "name": "daily-backup", "cron": "0 2 * * *", "enabled": true }, { "name": "weekly-archive", "cron": "0 0 * * 0", "enabled": false } ] } ``` ## Running the schedules ### Option 1 — long-lived DBDock process Use the programmatic API with `node-cron`. See [SDK → scheduling](/sdk/scheduling). ### Option 2 — external cron Let system cron trigger `dbdock backup` on the schedule you want: ``` 0 2 * * * cd /app && npx dbdock backup >> /var/log/dbdock.log 2>&1 ``` This bypasses `dbdock schedule` entirely and is the simplest option on a single server. ### Option 3 — cloud scheduler On Kubernetes (CronJob), AWS (EventBridge → Lambda/ECS), or GCP (Cloud Scheduler), trigger `dbdock backup` on the schedule. ## See also Detailed guide on running scheduled backups. View configured schedules. # dbdock status Source: https://docs.dbdock.xyz/cli/status View configured schedules and service health. ```bash theme={null} dbdock status ``` Shows configured schedules and, if DBDock is running as a long-lived process (via PM2), the service health. ## Sample output ``` 📅 Scheduled Backups: ┌─────┬──────────────┬─────────────────┬──────────┐ │ # │ Name │ Cron Expression │ Status │ ├─────┼──────────────┼─────────────────┼──────────┤ │ 1 │ daily │ 0 2 * * * │ ✓ Active │ │ 2 │ weekly │ 0 0 * * 0 │ ✗ Paused │ └─────┴──────────────┴─────────────────┴──────────┘ Total: 2 schedule(s) — 1 active, 1 paused 🚀 Service Status: 🟢 Running (PM2) PID: 12345 Uptime: 2d 5h Memory: 45.23 MB ``` ## When there's no service running If DBDock isn't running as a background process, the status section shows: ``` 🔴 Not running Schedules won't execute automatically. See https://docs.dbdock.xyz/alerts/scheduling for setup. ``` This is normal if you trigger backups via system cron or CI — schedules in the config file are only used when DBDock itself is the scheduler. ## Use cases * Check schedule configuration at a glance * Verify DBDock is running after a deploy * Quick health check before relying on a scheduled backup ## See also Add or modify schedules. Validate connections and alert config. # dbdock storage Source: https://docs.dbdock.xyz/cli/storage Show how much DBDock managed storage you've used against your plan's quota. ```bash theme={null} npx dbdock storage [options] ``` Shows your [DBDock Storage](/storage/managed) usage against your plan's quota. Requires a signed-in account ([`dbdock login`](/cli/login)). ## Quick example ```bash theme={null} dbdock storage ``` ``` DBDock Managed Storage [████░░░░░░░░░░░░░░░░░░░░] 12% 118.4 MB of 1.0 GB used (1 GB plan) ``` Usage is measured from what's actually stored, so both CLI and dashboard backups count toward it. ## Notes * If managed storage isn't on your plan, the command explains how to upgrade. * If you haven't activated it yet, run [`dbdock init`](/cli/init) and choose **DBDock Storage**. * At 90%+ usage, the command warns you to free up space or upgrade. ## Options | Option | Description | | ------------------ | ------------------------------------------------------ | | `--profile ` | Use a specific saved profile instead of the active one | ## See also How managed storage works. Your plan and limits. # dbdock sync Source: https://docs.dbdock.xyz/cli/sync Synchronize a local DBDock project with DBDock Cloud — push local config metadata, check status, pull the cloud baseline, and resolve conflicts. Secrets never sync. ```bash theme={null} npx dbdock sync [status|push|pull] [options] ``` Mirrors this project's configuration metadata to your DBDock Cloud dashboard. With no action, `sync` pushes local changes. For the concepts and workflow, see [Syncing a project](/cloud-sync/sync). Only non-secret metadata is uploaded — passwords, keys, and webhook URLs stay local. See [Data handling](/cloud-sync/data-handling). ## Prerequisites * Signed in with [`dbdock login`](/cli/login) * Project linked with [`dbdock init`](/cli/init) ## Actions | Action | Description | | -------------------- | ---------------------------------------------------------------- | | `dbdock sync` | Push local metadata to the cloud (default). | | `dbdock sync status` | Compare local vs. cloud — revisions, pending changes, last sync. | | `dbdock sync pull` | Adopt the cloud baseline as your local starting point. | ## Options | Option | Description | | --------- | ------------------------------------------------------------------------------- | | `--force` | Overwrite cloud state with local. Resolves a conflict in favor of your machine. | ## Examples ```bash Push theme={null} dbdock sync # → Synced. 1 change set(s) pushed. ``` ```bash Status theme={null} dbdock sync status # Project: proj_... # Local: revision 7 # Cloud: revision 7 # In sync. ``` ```bash Resolve a conflict (keep local) theme={null} dbdock sync --force ``` ## Conflicts If the cloud has diverged from the baseline your machine last saw, `sync` stops and exits `1` rather than guess: ```text theme={null} Cloud has diverged from your local baseline (conflict). Resolve with `dbdock sync pull` (adopt cloud) or `dbdock sync --force` (overwrite cloud). ``` Conflict snapshots are saved under `.dbdock/conflicts/` so nothing is lost while you decide. ## Exit codes | Code | Meaning | | ---- | ------------------------------------------------- | | `0` | Synced, or already up to date | | `1` | Conflict, not authenticated, or no linked project | ## Related Jump to this project in the dashboard. The full picture. # dbdock test Source: https://docs.dbdock.xyz/cli/test Validate your database, storage, and alert configuration. ```bash theme={null} npx dbdock test ``` Runs connectivity and configuration checks without creating a backup. Always run this after `dbdock init`, after changing credentials, or before relying on DBDock in production. ## What it checks Connects to Postgres, runs a test query, verifies `pg_dump` availability. Authenticates with the storage provider and attempts a list + upload of a tiny test object. Validates `DBDOCK_ENCRYPTION_SECRET` exists and is a valid 64-char hex key (if encryption is enabled). Sends a test notification to configured Slack/email channels (if enabled). ## Sample output ``` Running DBDock self-test... ✓ Database connection postgres@localhost:5432/myapp — 127ms ✓ pg_dump available pg_dump 16.2 (Homebrew) ✓ Storage: AWS S3 Bucket: my-backups (us-east-1) List: OK Upload: OK Delete test object: OK ✓ Encryption Secret: 64-char hex key ✓ Iterations: 100,000 ✓ Alerts Slack: webhook reachable ✓ Email: SMTP auth OK ✓ All checks passed — DBDock is ready to go. ``` ## When a check fails Failed checks tell you exactly what to fix: ``` ✗ Database connection Error: password authentication failed for user "postgres" Check: • DBDOCK_DB_PASSWORD is set in .env • DBDOCK_DB_URL is correct (if using URL mode) • Your Postgres server is running and reachable ``` Exit code is `1` on any failure — safe to use in CI as a preflight. ## Use in CI Add a preflight step to your pipeline: ```yaml theme={null} - name: DBDock preflight run: npx dbdock test env: DBDOCK_DB_URL: ${{ secrets.DATABASE_URL }} DBDOCK_STORAGE_ACCESS_KEY: ${{ secrets.AWS_KEY }} DBDOCK_STORAGE_SECRET_KEY: ${{ secrets.AWS_SECRET }} DBDOCK_ENCRYPTION_SECRET: ${{ secrets.DBDOCK_KEY }} ``` If anything is misconfigured, the deploy fails fast instead of silently producing broken backups. ## See also What to do when a check fails. # Authentication Source: https://docs.dbdock.xyz/cloud-sync/authentication Sign in to DBDock Cloud from the CLI with browser OAuth, check your identity with whoami, use tokens for CI, and manage multiple accounts with profiles. Before you can sync, the CLI needs to know who you are. DBDock uses browser-based **OAuth** — the same secure sign-in as the dashboard — so there's no long-lived API key to create or store in plaintext. ## Sign in ```bash theme={null} dbdock login ``` This opens your browser to authorize the CLI. Once you approve, DBDock stores your credentials locally and confirms the account: ```text theme={null} Logged in as you@example.com (profile: default) ``` If the browser doesn't open automatically, the CLI prints a URL you can visit manually. Credentials are saved under your DBDock home directory (`~/.dbdock/`), not in your project. ## Check who you are ```bash theme={null} dbdock whoami ``` ```text theme={null} User: you@example.com ID: user_... Auth: oauth Org: (none) Profile: default → https://api.dbdock.xyz/api/v1 ``` ## Sign out ```bash theme={null} dbdock logout ``` Removes the stored credentials for the active profile. Your project's `.dbdock/` link is left untouched — sign back in later and continue. ## Tokens for CI Interactive browser sign-in isn't available in automation. For CI, provide a token instead: ```bash theme={null} dbdock login --token "$DBDOCK_TOKEN" # or set the environment variable and DBDock picks it up export DBDOCK_TOKEN="..." ``` Treat `DBDOCK_TOKEN` like any other secret — inject it from your CI provider's secret store, never commit it. See [Key management](/security/key-management). ## Multiple accounts with profiles If you work with more than one DBDock account (say, personal and work), use profiles: ```bash theme={null} dbdock login --profile work dbdock whoami --profile work dbdock logout --profile work ``` Each profile stores its own credentials and API endpoint. Commands use the `default` profile unless you pass `--profile`. ## Organizations ```bash theme={null} dbdock switch-org --org ``` Organizations are forward-compatible — accounts are single-scope today, and this command sets a value for when multi-org support ships. You can safely ignore it for now. ## Environment variables A token to authenticate with instead of the browser flow. Useful in CI. Override the API endpoint. Defaults to `https://api.dbdock.xyz/api/v1`. Override the dashboard URL used by `dbdock open`. Defaults to `https://dbdock.xyz`. Where global credentials and config live. Defaults to `~/.dbdock`. ## Next Now that you're signed in, push your project to the cloud. # Data Handling Source: https://docs.dbdock.xyz/cloud-sync/data-handling Exactly what DBDock Cloud Sync uploads and what it never touches. Secrets — passwords, keys, webhook URLs — stay on your machine; only non-sensitive metadata syncs. Cloud Sync is deliberately conservative about what leaves your machine. This page is the exact contract: what syncs, what doesn't, and why. ## The rule **Only non-secret metadata syncs. Credentials never do.** DBDock builds the sync payload directly from your `dbdock.config.json`, and the collector drops every secret before anything is sent. Where a secret's *presence* is useful (for example, "encryption is enabled"), it's represented as a boolean flag — never the value. ## What syncs Database `type`, `host`, `port`, `database` name, and `user`. **Not** the password. Provider and non-secret settings such as bucket name, region, and endpoint. **Not** access keys, secret keys, or API secrets — those are represented only as presence flags. Format, whether compression is enabled, whether encryption is enabled, and retention settings. **Not** the encryption secret. Schedule name, cron expression, and enabled state. Channel type and non-secret settings. **Not** webhook URLs, Slack tokens, or SMTP passwords. ## What never syncs These values are never included in a sync payload, by design: * Database passwords * Storage access keys, secret keys, and Cloudinary API secrets * Backup encryption secrets * SMTP passwords * Slack and custom webhook URLs Your backups themselves are also not part of sync. Sync mirrors *configuration metadata*, not backup files or database contents. Backup files go to your chosen [storage](/cloud/storage); Cloud Sync only records that a backup exists and its non-sensitive attributes. ## Why it's built this way Secrets belong in your environment, not in a config file and not in a remote mirror. This is the same principle the CLI follows everywhere — see [`dbdock migrate-config`](/cli/migrate-config), which moves secrets out of config files into environment variables. Cloud Sync extends that principle across the wire: the dashboard can show you *what* you have configured without ever holding the keys to it. ## Where it's stored locally The link and last-synced state live in your project under `.dbdock/`. Your global credentials live under `~/.dbdock/` (override with `DBDOCK_HOME`). Add `.dbdock/` to your `.gitignore` if you don't want the link committed. ## Related How the cloud stores and isolates data. Where secrets should live. # Cloud Sync Source: https://docs.dbdock.xyz/cloud-sync/overview Link a local DBDock CLI project to your DBDock Cloud dashboard. Automate from the terminal, monitor from the browser — and keep secrets on your machine, because only metadata syncs. Cloud Sync connects a local [CLI](/cli/overview) project to your [DBDock Cloud](/cloud/overview) account. Configure and run DBDock from the terminal, and see the same project — its connection, storage, schedules, and backup metadata — in the dashboard. **Secrets stay on your machine.** Sync uploads only non-sensitive metadata. Database passwords, storage keys, encryption secrets, and webhook URLs are never sent. See [Data handling](/cloud-sync/data-handling). ## Why link them Script and automate locally; monitor, share, and review from a managed dashboard. Your `dbdock.config.json` stays authoritative. The dashboard mirrors it. Give teammates a read on what's configured without sharing your machine. Metadata-only sync means linking a project never exports a credential. ## How it works DBDock keeps a small `.dbdock/` folder in your project that records which cloud project this directory is linked to and the last state it synced. Running `dbdock sync` compares your local config to the cloud baseline and pushes the differences. ```text theme={null} your-project/ ├── dbdock.config.json # your configuration (authoritative) └── .dbdock/ ├── config.json # linked project id ├── state.json # last synced revision └── conflicts/ # saved conflict snapshots, if any ``` Run [`dbdock login`](/cli/login) to authenticate to DBDock Cloud in your browser. Run [`dbdock init`](/cli/init) — it offers to link this directory to a cloud project. (Already have a config? It links the existing one.) Run [`dbdock sync`](/cli/sync) to push your local metadata to the dashboard. Use `dbdock open` to jump to it in the browser. ## Everyday commands | Command | What it does | | ---------------------------- | ---------------------------------- | | [`dbdock login`](/cli/login) | Sign in to DBDock Cloud | | `dbdock whoami` | Show the signed-in account | | [`dbdock sync`](/cli/sync) | Push local metadata to the cloud | | `dbdock sync status` | Compare local vs. cloud | | `dbdock sync pull` | Adopt the cloud baseline | | [`dbdock open`](/cli/open) | Open this project in the dashboard | | `dbdock logout` | Remove stored credentials | ## Next Sign in, profiles, and tokens. Push, pull, status, and conflicts. # Syncing a Project Source: https://docs.dbdock.xyz/cloud-sync/sync Push local DBDock config to the cloud, check sync status, pull the cloud baseline, and resolve conflicts with dbdock sync — plus opening the linked project in the dashboard. Once you're [signed in](/cloud-sync/authentication) and the project is [linked](/cli/init), `dbdock sync` keeps your dashboard in step with your local configuration. ## Push local changes ```bash theme={null} dbdock sync ``` This reads your `dbdock.config.json`, compares it to the last synced state, and pushes the differences to DBDock Cloud. ```text theme={null} Synced. 1 change set(s) pushed. ``` If nothing changed, it says so and does nothing: ```text theme={null} Nothing to sync — local metadata matches cloud. ``` Only non-secret metadata is sent. See exactly what leaves your machine in [Data handling](/cloud-sync/data-handling). ## Check status ```bash theme={null} dbdock sync status ``` ```text theme={null} Project: proj_... Local: revision 7 Cloud: revision 7 Pending: 0 Last sync: 2026-07-18T09:12:00Z In sync. ``` Status works offline too — if the cloud is unreachable it reports `unreachable (offline)` and shows your pending local changes so you know what will push once you're back online. ## Pull the cloud baseline ```bash theme={null} dbdock sync pull ``` Adopts the current cloud revision as your local baseline. Use it to align a fresh checkout, or as one side of resolving a conflict. ## Resolving conflicts A conflict means the cloud has diverged from the baseline your machine last saw — for example, the project changed from another machine. `dbdock sync` stops rather than guess: ```text theme={null} Cloud has diverged from your local baseline (conflict). Resolve with `dbdock sync pull` (adopt cloud) or `dbdock sync --force` (overwrite cloud). ``` You choose which side wins: ```bash theme={null} dbdock sync pull ``` Adopt the cloud state as your new baseline, then re-apply local changes if needed. ```bash theme={null} dbdock sync --force ``` Overwrite the cloud with your local metadata. DBDock saves conflict snapshots under `.dbdock/conflicts/` so nothing is lost while you decide. ## Open the dashboard ```bash theme={null} dbdock open ``` Opens this project in the DBDock dashboard. To print the URL instead of launching a browser (handy over SSH): ```bash theme={null} dbdock open --print ``` `dbdock open` needs a linked project. If you see "No linked project," run [`dbdock init`](/cli/init) first to link this directory. ## Offline and retries Sync is resilient. Change sets are queued locally and drained to the cloud; if a push fails, it's retried on the next sync. `dbdock sync status` shows pending items and flags any that need attention. ## Related What syncs, and what never does. Command flags and exit codes. # Backups & Restore Source: https://docs.dbdock.xyz/cloud/backups Create encrypted, compressed database backups in DBDock Cloud, restore them, retry failures, download files, and apply retention — on demand or on a schedule. A backup is a point-in-time snapshot of a connected database, encrypted and compressed, stored in your chosen [storage](/cloud/storage). DBDock Cloud runs the same engines as the [CLI](/cli/overview) — see [Concepts](/core/concepts) for the backup pipeline and formats. ## Create a backup Choose the [connection](/cloud/connections) to back up. Select managed storage or one of your own buckets. Defaults to your primary storage. Watch live progress. When it finishes, the backup appears in the list with its size, duration, and status. To run backups automatically, create a [schedule](/cloud/schedules) instead of starting them by hand. ## Restore a backup Open any completed backup and choose **Restore**. You can restore into the original database or a different connection — useful for [refreshing staging](/guides/staging-refresh) from production. Restoring overwrites data in the target database. Double-check the target connection before you confirm. ## Manage backups Failed backups can be retried from the list. The logs explain what went wrong — a common cause is an unreachable database or a storage credential issue. Download the encrypted backup file to keep an off-platform copy. You'll need your encryption secret to restore it later — see [Key management](/security/key-management). Every backup keeps detailed logs, including timing and any errors, so you can diagnose issues without guesswork. Remove a backup you no longer need. See [Deletion safety](/storage/deletion-safety) for how DBDock protects against accidental data loss. ## Retention Instead of deleting backups by hand, set a retention policy so DBDock keeps the right number and cleans up the rest automatically. Retention has three controls — a maximum count, a maximum age, and a floor that's never crossed. See [Retention strategies](/guides/retention-strategies). ## Encryption Backups are encrypted with **AES-256-GCM**. On paid plans, encryption is on by default. The encryption secret is what makes a backup restorable — store it safely and separately from the backups themselves. See [Encryption](/security/encryption). ## Related Automate backups with cron. Where backups are stored. # Plans & Billing Source: https://docs.dbdock.xyz/cloud/billing DBDock Cloud plans — Free, Pro, and Business. What each unlocks: connections, scheduled backups, managed storage, encryption, team seats, alerts, and admin panels. DBDock Cloud has three plans. The free plan is genuinely useful on its own; paid plans raise limits and unlock automation, encryption, and team features. Limits change as plans evolve. This page describes what each plan unlocks; for the authoritative, up-to-date numbers and prices, see the [pricing page](https://dbdock.xyz/pricing). ## Plans at a glance | | Free | Pro | Business | | ------------------------- | ---------- | ------- | -------------- | | Managed storage | 1 GB | 50 GB | 100 GB | | Connections | A couple | Many | Lots | | Scheduled backups | — | ✓ | ✓ | | Encrypted backups | — | ✓ | ✓ | | Incremental backups | — | ✓ | ✓ | | Cross-database migrations | Trial | ✓ | ✓ | | Database copies | Trial | ✓ | ✓ | | Slack & webhook alerts | Email only | ✓ | ✓ | | Team members | — | ✓ | ✓ (more seats) | | Admin panels | 1 | Several | Many | Every plan includes DBDock managed storage and at least one alert channel, so you can back up and be notified from day one. The exact counts per plan live on the [pricing page](https://dbdock.xyz/pricing). ## Managed storage quota DBDock meters your managed-storage usage. As you approach your quota you'll see an in-app banner, and on eligible plans an email. If you hit the limit, new managed-storage backups are held off until you free space or upgrade — existing backups are never deleted to make room. Route large or long-lived backups to [your own bucket](/cloud/storage) to keep managed storage lean. ## Upgrade, downgrade, and the portal Manage your subscription from **Billing** in the dashboard. Upgrades take effect immediately so new limits apply right away. Billing and invoices are handled through the customer portal linked from that page. ## What counts against limits * **Backups per month** — counted per completed backup run, across manual and scheduled. * **Migrations and copies per month** — counted per job. * **Connections, schedules, alerts, admin panels** — counted by how many exist, not how often they run. ## Related Managed vs. your own bucket. Seats and shared workspaces. # Connections Source: https://docs.dbdock.xyz/cloud/connections Add and manage database connections in DBDock Cloud — nine supported engines, connection testing, encrypted credentials, and database size tracking. A **connection** is a database DBDock talks to. Everything else — backups, schedules, migrations, alerts — builds on a connection. ## Supported databases DBDock Cloud connects to nine database types: ## Add a connection Give it a recognizable name — this is how it appears across backups, schedules, and alerts. Provide host, port, database name, and credentials. For databases that require TLS, enable SSL. DBDock encrypts stored credentials at rest. Use **Test connection** to confirm DBDock can reach the database before saving. This catches firewall, credential, and SSL issues early. DBDock connects to your database over the network, so it must be reachable from DBDock Cloud. If your database is only accessible from a private network, allowlist DBDock's egress or use the [CLI](/cli/overview), which runs inside your own environment. ## Database size tracking DBDock periodically measures each connected database's size and shows the trend on your dashboard and in [Analytics](/cloud/overview). This is metadata only — DBDock reads size, never your table contents, outside of an explicit backup or migration you start. ## Plan limits The number of connections you can add depends on your plan. See [Billing](/cloud/billing) for current limits, or the [pricing page](https://dbdock.xyz/pricing) for the authoritative numbers. ## Related Once a connection exists, back it up. How credentials are stored and isolated. # MCP Server Source: https://docs.dbdock.xyz/cloud/mcp Connect AI assistants like Claude and Cursor to DBDock Cloud over the Model Context Protocol — run backups, restores, copies, migrations, and schedules from your editor with secure OAuth sign-in. DBDock Cloud exposes a hosted [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server, so AI assistants can operate your DBDock account on your behalf — safely, with your permission, over secure OAuth sign-in. ## Endpoint ```text theme={null} https://dbdock.xyz/api/mcp ``` The server uses the streamable HTTP transport and browser-based **OAuth** sign-in. There are no API keys to create or paste — you approve access in your browser, the same way you sign in to the dashboard. ## Connect a client ```bash theme={null} claude mcp add --transport http dbdock https://dbdock.xyz/api/mcp ``` Or add it to your MCP config: ```json theme={null} { "mcpServers": { "dbdock": { "type": "http", "url": "https://dbdock.xyz/api/mcp" } } } ``` Add to your MCP configuration: ```json theme={null} { "mcpServers": { "dbdock": { "url": "https://dbdock.xyz/api/mcp" } } } ``` Any MCP client that supports the HTTP transport can connect. Point it at `https://dbdock.xyz/api/mcp` and complete the OAuth sign-in when prompted. The first time a client connects, your browser opens to authorize it. After that, the client acts within your DBDock account. ## What the assistant can do Once connected, the assistant can call DBDock tools such as: See the databases in your account. Start a backup of a connection. Restore a backup into a database. Clone one database into another. Run a cross-database migration. Inspect and control schedules. MCP tools act on real databases. Backups, restores, and copies through the assistant have the same effect as running them in the dashboard — review what an assistant proposes before you approve it, especially restores and copies, which overwrite data. ## Security The MCP server authenticates every request through DBDock's OAuth flow and scopes access to your own account. It never exposes your database credentials to the client — the assistant asks DBDock to perform actions; it doesn't receive your secrets. See [Cloud security](/security/cloud). # DBDock Cloud Source: https://docs.dbdock.xyz/cloud/overview DBDock Cloud is the managed dashboard at dbdock.xyz — connections, encrypted backups, scheduling, storage, migrations, analytics, alerts, teams, and admin panels, with nothing to self-host. DBDock Cloud is the hosted version of DBDock, at [dbdock.xyz](https://dbdock.xyz). It runs the same backup and migration engines as the [CLI](/cli/overview), but the scheduling, storage, and job execution are managed for you. Sign in with OAuth — no password to manage. ## What's inside Connect nine database types. Test reachability and track database size over time. Encrypted, compressed backups on demand or on a schedule. Restore, retry, and download. DBDock managed storage, or bring your own S3, R2, or Cloudinary bucket. Clone a database between environments without leaving the browser. Cross-database migration between MongoDB and PostgreSQL. Cron-based automation with retries and full run history. Watch row counts and database sizes trend over time. Email, Slack, and webhook notifications for job events. Build no-code, shareable admin dashboards from a PostgreSQL database. Invite people into a shared workspace to manage databases together. Connect AI assistants to your DBDock account over the Model Context Protocol. Plans, entitlements, and managed-storage quota. ## Cloud vs. CLI Both surfaces share the same engines and file formats. The difference is where the work runs and what's managed. | | DBDock Cloud | DBDock CLI | | ------------- | ------------------------------------------- | ---------------------------- | | Where it runs | Hosted at dbdock.xyz | Your machine or CI | | Scheduling | Managed — DBDock runs your jobs | Your own cron / scheduler | | Storage | Managed storage included, or bring your own | Bring your own | | Team access | Shared workspaces | Per-machine | | License | Managed subscription | Open source (MIT) | | Best for | Hands-off, always-on operations | Local control, scripting, CI | You don't have to choose. [Cloud Sync](/cloud-sync/overview) links a local project to your dashboard so you get both — terminal control and a managed, always-on view. ## Getting started First backup in five minutes. What each plan includes. # Schedules Source: https://docs.dbdock.xyz/cloud/schedules Automate backups in DBDock Cloud with cron-based schedules that run for you — with retries, per-schedule run history, and skip controls. A schedule runs a backup automatically on a cron cadence. DBDock Cloud executes it for you — there's no cron daemon to run or server to keep awake. ## Create a schedule Choose the [connection](/cloud/connections) and [storage](/cloud/storage) destination. Pick a cron expression — for example, `0 2 * * *` for every night at 2 AM. DBDock queues the next run and shows when it will happen next on your dashboard's **Up next**. ## Run history Each schedule keeps a full history of its runs. Open a schedule to see every backup it produced, with status, timing, and logs — so you can confirm last night's job succeeded at a glance. ## Reliability Transient failures are retried automatically, so a brief network blip doesn't cost you a backup. Skip the next scheduled run — handy before planned maintenance — without deleting the schedule. Schedules run in the cloud even when your machine is off. To automate from your own environment instead, use [`dbdock schedule`](/cli/schedule) in the CLI. ## Alerts Pair schedules with [alerts](/alerts/overview) so you hear about failures immediately over email, Slack, or a webhook — instead of discovering them when you need a restore. ## Plan availability Scheduling is available on paid plans, with per-plan limits on how many schedules you can run. See [Billing](/cloud/billing). ## Related What each run produces. Get notified on failure. # Storage Source: https://docs.dbdock.xyz/cloud/storage Store DBDock Cloud backups in included managed storage or bring your own bucket — AWS S3, Cloudflare R2, or Cloudinary — with per-plan quotas and usage tracking. Storage is where your backups live. DBDock Cloud gives you two options, and you can use both at once. ## Managed storage Every account includes **DBDock managed storage** — encrypted, metered, and ready with zero setup. The free plan includes **1 GB at no cost**; paid plans include more. See [Billing](/cloud/billing) for current quotas and the [pricing page](https://dbdock.xyz/pricing) for authoritative numbers. DBDock meters managed-storage usage and warns you as you approach your quota, so a backup never fails silently for lack of space. When you're close to the limit, you'll see an in-app banner and (on eligible plans) an email. ## Bring your own bucket Prefer to keep backups in infrastructure you control — for compliance, data residency, or a second copy? Connect your own provider: S3 and any S3-compatible store. Zero-egress object storage. Media-focused storage. When you add a bucket, DBDock stores only what it needs to write and read backups, and encrypts those credentials at rest. Backups written to your bucket are still encrypted by DBDock before they leave. ## Add a bucket Choose a provider. Provide the bucket name, region, endpoint (for S3-compatible providers), and access keys. DBDock validates them before saving. Pick the bucket as the destination when you create a [backup](/cloud/backups) or a [schedule](/cloud/schedules), or set it as your default. ## Deletion safety DBDock will not silently orphan or wipe backups. Managed storage stays put as part of your plan, and destructive actions on your own buckets are guarded. See [Deletion safety](/storage/deletion-safety). ## Related Provider-by-provider setup. Managed-storage quotas by plan. # Team Source: https://docs.dbdock.xyz/cloud/teams Invite people into a shared DBDock Cloud workspace so they can manage connections, backups, and schedules alongside you, acting on the owner's resources. A team lets more than one person work in the same DBDock workspace. Members manage the same connections, backups, storage, and schedules — no sharing of a single login required. ## How it works The workspace has an **owner** and **members**. Members act on the owner's resources: they see the same connections and backups, and their actions run against the owner's account and plan. This keeps billing and quotas in one place while giving your team shared access. You'll see your workspace, current members, and available seats. Send an invite by email. The recipient accepts, signs in, and joins your workspace. Remove members or re-invite as your team changes. ## Plan availability Team members are a paid feature, with a per-plan seat limit. If your plan doesn't include team seats yet, you'll be prompted to upgrade when you try to invite someone. See [Billing](/cloud/billing). Because members act on the owner's resources, everyone shares the workspace's managed-storage quota and job limits. Plan seats and quotas together — see the [pricing page](https://dbdock.xyz/pricing). ## Related Seats and plan limits. Workspace isolation and access. # Concepts Source: https://docs.dbdock.xyz/core/concepts How DBDock thinks about backups, compression, encryption, and storage. This page explains the mental model behind DBDock. Reading it once will make every other page easier to follow. ## Backup anatomy A DBDock backup is always one file per backup. The filename encodes when it was taken: ``` backup-YYYY-MM-DD-HH-MM-SS-BACKUPID.sql ``` Wherever the backup lives — local disk, S3, R2, or Cloudinary — it follows the same naming pattern. A parallel metadata record (size, duration, compression info, encryption info) is stored alongside it, which is how `dbdock list`, `dbdock restore`, and retention policies know what's available. ## The pipeline Every backup flows through the same stages: ``` pg_dump ──▶ [compress] ──▶ [encrypt] ──▶ storage adapter ──▶ destination ``` Each stage is optional except `pg_dump` and the destination. This is why you can: * Skip compression for tiny DBs where speed matters more than size * Skip encryption on local-only backups if you manage the disk * Change storage providers without re-dumping your database Restore runs the pipeline in reverse: ``` storage adapter ──▶ [decrypt] ──▶ [decompress] ──▶ pg_restore ──▶ database ``` ## Backup formats DBDock supports all four PostgreSQL formats from `pg_dump`: | Format | Extension | When to use | | ------------------ | --------- | --------------------------------------------------------------------------------- | | `custom` (default) | `.sql` | Best for most cases — binary, compressed by pg\_dump, selective restore supported | | `plain` | `.sql` | Human-readable SQL, works with `psql` directly | | `directory` | `.dir` | Parallel dump/restore for very large DBs | | `tar` | `.tar` | Tar archive of the directory format | Set format in `dbdock.config.json`: ```json theme={null} { "backup": { "format": "custom" } } ``` ## Compression DBDock uses [zstd](https://github.com/facebook/zstd) for compression. zstd is fast and compresses roughly as well as gzip at higher levels. * **Level 0** — no compression * **Level 6** (default) — balanced * **Level 11** — maximum compression, slower Compression is applied *after* `pg_dump`, so it works regardless of backup format. ## Encryption DBDock encrypts with **AES-256-GCM**. The key is derived from `DBDOCK_ENCRYPTION_SECRET` using **PBKDF2** with 100,000 iterations (configurable). * Encryption is applied *after* compression, so encrypted backups are also compressed. * The IV is generated fresh per backup and stored in the file header alongside the ciphertext. * Losing the secret = losing the ability to restore. Store it somewhere other than the backup destination. See the [Security page](/security/overview) for key management guidance. ## Storage adapters DBDock ships adapters for four storage backends. They all implement the same interface — `put`, `get`, `list`, `delete` — so swapping providers never requires changing how you use the CLI. Disk-based storage. S3 and any S3-compatible object store. Zero-egress object storage. Media-focused storage service. ## Retention Without cleanup, backups accumulate. DBDock applies a retention policy with three knobs: * `maxBackups` — cap the total count * `maxAgeDays` — delete backups older than N days * `minBackups` — *never* delete below this count, no matter what `minBackups` is the safety net — even if every other rule says "delete," DBDock will refuse to go below it. See [Retention strategies](/guides/retention-strategies) for recommended settings. ## The config file `dbdock.config.json` holds non-sensitive configuration and is safe to commit. It has four top-level sections: ```json theme={null} { "database": { ... }, "storage": { ... }, "backup": { ... }, "alerts": { ... } } ``` Secrets (passwords, keys, webhooks) never go in the config file — they live in environment variables. See the [Configuration reference](/core/configuration) for every available option. ## Programmatic use Everything the CLI does, you can do from code. DBDock exports a small NestJS-based module that exposes `BackupService`, `StorageService`, and `CryptoService`: ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); await backups.createBackup({ compress: true, encrypt: true }); ``` See the [SDK overview](/sdk/overview) for the full API surface. # Configuration Source: https://docs.dbdock.xyz/core/configuration Complete reference for dbdock.config.json and environment variables. DBDock can be configured via `dbdock.config.json`, environment variables, or a mix of both. Secrets always live in environment variables — never in the config file. **Security-first.** Passwords, API keys, webhooks, and encryption secrets must be set via environment variables. The config file is designed to be committed to your repository; the `.env` file is designed not to be. ## Config file structure `dbdock.config.json` has four top-level sections: ```json theme={null} { "database": { /* connection details (no password) */ }, "storage": { /* storage provider config */ }, "backup": { /* format, compression, encryption, retention */ }, "alerts": { /* email & slack notifications */ } } ``` ## Database ### Option 1 — URL via environment (recommended) Set `DBDOCK_DB_URL` or `DATABASE_URL` to a full PostgreSQL URL. When present, it overrides anything in `dbdock.config.json`. ```bash theme={null} DBDOCK_DB_URL=postgresql://user:password@host:5432/database # or DATABASE_URL=postgresql://user:password@host:5432/database ``` ### Option 2 — Config file with password in env ```json theme={null} { "database": { "type": "postgres", "host": "localhost", "port": 5432, "username": "postgres", "database": "myapp" } } ``` Password comes from `DBDOCK_DB_PASSWORD`. ### Option 3 — `.pgpass` For host-level credential isolation, use PostgreSQL's `.pgpass` file: ```bash theme={null} touch ~/.pgpass chmod 600 ~/.pgpass echo "localhost:5432:myapp:postgres:my-secure-password" >> ~/.pgpass ``` DBDock uses `.pgpass` automatically when present. ## Storage Pick one provider. Each has its own dedicated page with setup instructions: Filesystem storage for single-server setups. S3 or any S3-compatible service. Zero-egress object storage. Media platform with generous free tier. ## Backup ```json theme={null} { "backup": { "format": "custom", "compression": { "enabled": true, "level": 6 }, "encryption": { "enabled": true }, "retention": { "enabled": true, "maxBackups": 100, "maxAgeDays": 30, "minBackups": 5, "runAfterBackup": true } } } ``` | Field | Type | Default | Description | | -------------------------- | --------------------------------------------- | ---------- | -------------------------------- | | `format` | `'custom' \| 'plain' \| 'directory' \| 'tar'` | `'custom'` | PostgreSQL backup format | | `compression.enabled` | boolean | `true` | Apply zstd compression | | `compression.level` | 0–11 | `6` | zstd compression level | | `encryption.enabled` | boolean | `true` | AES-256-GCM encryption | | `retention.enabled` | boolean | `true` | Enable automatic cleanup | | `retention.maxBackups` | number | `100` | Cap total backup count | | `retention.maxAgeDays` | number | `30` | Delete backups older than N days | | `retention.minBackups` | number | `5` | Never delete below this count | | `retention.runAfterBackup` | boolean | `true` | Run cleanup after each backup | Encryption key is read from `DBDOCK_ENCRYPTION_SECRET`. Generate a key: ```bash theme={null} node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` ## Alerts See the dedicated alert pages for setup: SMTP via Gmail, SendGrid, SES, Mailgun, or any provider. Incoming webhooks. ## Environment variables reference DBDock reads from both `.env` and `.env.local`. `.env.local` takes priority. ### Database | Variable | Description | | -------------------- | ------------------------------------------ | | `DBDOCK_DB_URL` | Full PostgreSQL URL | | `DATABASE_URL` | Same as `DBDOCK_DB_URL` (alternative name) | | `DBDOCK_DB_PASSWORD` | Password (when not using URL form) | | `DB_HOST` | Database host | | `DB_PORT` | Database port | | `DB_USER` | Database user | | `DB_NAME` | Database name | ### Storage | Variable | Description | | ------------------------------ | --------------------------------------- | | `STORAGE_PROVIDER` | `local` \| `s3` \| `r2` \| `cloudinary` | | `STORAGE_BUCKET` | Bucket/container name | | `STORAGE_LOCAL_PATH` | Path for local storage | | `DBDOCK_STORAGE_ACCESS_KEY` | S3/R2 access key | | `DBDOCK_STORAGE_SECRET_KEY` | S3/R2 secret key | | `DBDOCK_CLOUDINARY_API_KEY` | Cloudinary API key | | `DBDOCK_CLOUDINARY_API_SECRET` | Cloudinary API secret | ### Encryption | Variable | Description | | -------------------------- | ------------------------------------ | | `DBDOCK_ENCRYPTION_SECRET` | 64-char hex key | | `ENCRYPTION_ENABLED` | `true` \| `false` | | `ENCRYPTION_ITERATIONS` | PBKDF2 iterations (default `100000`) | ### Alerts | Variable | Description | | ----------------------- | -------------------------- | | `DBDOCK_SMTP_USER` | SMTP username | | `DBDOCK_SMTP_PASS` | SMTP password | | `DBDOCK_SLACK_WEBHOOK` | Slack incoming webhook URL | | `DBDOCK_CUSTOM_WEBHOOK` | Custom HTTP webhook URL | ### Runtime | Variable | Description | | -------------------- | -------------------------------------------------------------- | | `DBDOCK_CONFIG_PATH` | Path to `dbdock.config.json` (default: `./dbdock.config.json`) | | `DBDOCK_STRICT_MODE` | `true` to refuse any secret read from the config file | ## Strict mode Set `DBDOCK_STRICT_MODE=true` to enforce environment-only secrets. DBDock will refuse to load any configuration where a secret appears in the config file, preventing accidental commits. Recommended for CI and production. ## Config migration If you have secrets in `dbdock.config.json` from an older version: ```bash theme={null} npx dbdock migrate-config ``` DBDock moves them to `.env`, cleans up the config file, and updates `.gitignore`. See [`migrate-config`](/cli/migrate-config). # Installation Source: https://docs.dbdock.xyz/get-started/installation Install DBDock globally, use with npx, or add it as a library dependency. ## Prerequisites DBDock requires Node.js 18 or later. `pg_dump`, `pg_restore`, and `psql` must be on your `PATH`. ### Install PostgreSQL client tools ```bash theme={null} brew install postgresql ``` ```bash theme={null} sudo apt-get update sudo apt-get install postgresql-client ``` ```bash theme={null} sudo dnf install postgresql ``` Download the installer from the [PostgreSQL downloads page](https://www.postgresql.org/download/windows/). Select only the "Command Line Tools" component if you don't need the full server. Verify the tools are available: ```bash theme={null} pg_dump --version pg_restore --version psql --version ``` ## Install DBDock Always uses the latest published version. Best for one-off tasks. ```bash theme={null} npx dbdock --help ``` Best for daily use — `dbdock` is available from any directory. ```bash theme={null} npm install -g dbdock # or pnpm add -g dbdock # or yarn global add dbdock ``` Verify: ```bash theme={null} dbdock --version ``` Use DBDock programmatically in a Node.js app. ```bash theme={null} npm install dbdock ``` See the [SDK overview](/sdk/overview) to get started. ## Permission errors If `npm install -g` fails with `EACCES`: The recommended fix is to point npm at a directory you own: ```bash theme={null} mkdir -p ~/.npm-global npm config set prefix '~/.npm-global' echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc source ~/.zshrc npm install -g dbdock ``` Only if you understand the implications: ```bash theme={null} sudo npm install -g dbdock ``` ## Next steps Run your first backup in 5 minutes. Understand how DBDock thinks about backups. # CLI Quickstart Source: https://docs.dbdock.xyz/get-started/quickstart Go from zero to your first backup with the DBDock CLI in under 5 minutes — install, initialize, back up, and restore from your terminal. This guide takes you through setup, your first backup, and your first restore with the DBDock CLI. Total time: about 5 minutes. Prefer a dashboard? Follow the [Cloud Quickstart](/get-started/quickstart-cloud) instead. Want both? Do this, then [link the CLI to the cloud](/cloud-sync/overview). Haven't installed DBDock yet? See the [installation guide](/get-started/installation). ## 1. Initialize Run `init` once in your project directory. It walks you through everything interactively. ```bash theme={null} npx dbdock init ``` It will ask for: * Database connection (host, port, user, database name) * Storage provider (local disk, S3, R2, or Cloudinary) * Encryption (recommended for cloud storage) * Alerts (optional — Slack and email) **Security-first by default.** Non-sensitive config goes to `dbdock.config.json` (safe for git). Secrets go to `.env`, and `.gitignore` is updated automatically. ## 2. Create your first backup ```bash theme={null} npx dbdock backup ``` You'll see real-time progress: ``` ████████████████████ | 100% | 45.23/100 MB | Speed: 12.50 MB/s | ETA: 0s | Uploading to S3 ✔ Backup completed successfully ``` The backup is encrypted (if enabled), compressed, and streamed directly to your configured storage. ## 3. Restore a backup ```bash theme={null} npx dbdock restore ``` DBDock shows a list of backups and lets you pick one: ``` Progress: ──────────────────────────────────────────────────────── ✔ Downloading backup ✔ Decrypting data ✔ Decompressing data ⟳ Restoring to database... ──────────────────────────────────────────────────────── ✔ All steps completed in 8.42s ``` You can also restore into a **different** database. Pick "New Database Instance (Migrate)" when prompted and provide the target connection details — great for refreshing staging from production. ## 4. Verify everything works Before trusting DBDock in production, run the self-test: ```bash theme={null} npx dbdock test ``` This checks: * Database connection * Storage provider access * Alert configuration (if enabled) ## Environment-only setup (no config file) Prefer not to commit a config file? Run DBDock entirely from environment variables: ```bash theme={null} # .env DBDOCK_DB_URL=postgresql://user:password@host:5432/database STORAGE_PROVIDER=s3 STORAGE_BUCKET=my-backups DBDOCK_STORAGE_ACCESS_KEY=your-key DBDOCK_STORAGE_SECRET_KEY=your-secret DBDOCK_ENCRYPTION_SECRET=your-64-char-hex-key ``` Then: ```bash theme={null} npx dbdock backup ``` See the [configuration reference](/core/configuration) for all available variables. ## What to do next Every command, every flag, with examples. S3, R2, Cloudinary, or local disk. Slack, email, or custom webhooks. Automated cron-based backups. # Cloud Quickstart Source: https://docs.dbdock.xyz/get-started/quickstart-cloud Connect a database and take your first encrypted backup in DBDock Cloud in under five minutes — no installation, no infrastructure. This guide takes you from zero to your first backup in the [DBDock Cloud](https://dbdock.xyz) dashboard. No installation required. Prefer the terminal? Follow the [CLI Quickstart](/get-started/quickstart) instead — or do both and [link them with Cloud Sync](/cloud-sync/overview). Go to [dbdock.xyz](https://dbdock.xyz) and sign in. DBDock uses secure OAuth sign-in — there's no password to manage. Open **Connections → New connection** and enter your database details. DBDock supports PostgreSQL, MySQL, MariaDB, SQL Server, CockroachDB, Redshift, TimescaleDB, MongoDB, and Redis. Use **Test connection** to confirm DBDock can reach the database before saving. Credentials are encrypted at rest — see [Cloud security](/security/cloud). Every account includes **1 GB of DBDock managed storage, free** — nothing to configure. Prefer your own bucket? Add AWS S3, Cloudflare R2, or Cloudinary under **Storage**. See [Storage](/cloud/storage). Open **Backups → New backup**, pick your connection, and start it. You'll see live progress, and the finished backup appears in the list with its size and duration. Open **Schedules** and create a cron schedule — for example, every night at 2 AM. DBDock runs it for you and keeps a full run history. Scheduling is available on paid plans; see [Billing](/cloud/billing). ## Next steps Manage databases, test reachability, and track size over time. Restore, retry, download, and set retention. Get notified on success or failure via email, Slack, or webhooks. Automate from the terminal, monitor from the dashboard. # What is DBDock? Source: https://docs.dbdock.xyz/get-started/what-is-dbdock An overview of DBDock — the open-source CLI, the managed cloud dashboard, supported databases, and how the two surfaces stay in sync. DBDock is a database operations toolkit. It does the recurring, easy-to-get-wrong jobs — **backups, restores, copies, schedules, and cross-database migrations** — through one consistent tool, so you don't maintain a pile of `pg_dump`, `cron`, and upload scripts. ## Two surfaces, one toolkit The `dbdock` npm package. MIT licensed, self-hosted, runs anywhere Node.js runs — your laptop, a server, or CI. Nothing leaves your machine unless you ask it to. The hosted dashboard at [dbdock.xyz](https://dbdock.xyz). Managed storage, scheduled jobs that run for you, team access, analytics, and alerts — no infrastructure to operate. [Cloud Sync](/cloud-sync/overview) is the bridge: link a local CLI project to your cloud account so the dashboard reflects what you have configured locally. Crucially, **secrets never sync** — only non-sensitive metadata. See [Data handling](/cloud-sync/data-handling). ## Supported databases | Capability | PostgreSQL family | MySQL / MariaDB | SQL Server | MongoDB | Redis | | --------------------------- | ----------------- | --------------- | ---------- | ------------------ | ----- | | Backup & restore | ✓ | ✓ | ✓ | Cloud connect only | ✓ | | Database copy (same engine) | ✓ | ✓ | ✓ | — | — | | Cross-database migration | ✓ (↔ MongoDB) | — | — | ✓ (↔ PostgreSQL) | — | The **PostgreSQL family** includes PostgreSQL, CockroachDB, Redshift, and TimescaleDB. In DBDock Cloud you can connect nine database types; the CLI's backup engines cover the PostgreSQL family, MySQL/MariaDB, SQL Server, and Redis. Cross-database migration is MongoDB ↔ PostgreSQL. ## What it's good at * **Reliable backups** — encrypted with AES-256-GCM and compressed with zstd, stored wherever you choose. * **Fast restores** — pick a backup and restore interactively, or automate it. * **Environment cloning** — copy prod to staging or staging to local with one command. * **Cross-database migration** — move between MongoDB and PostgreSQL with schema mapping and dry runs. * **Hands-off automation** — cron schedules that run in the cloud, with alerts when something needs your attention. ## Who it's for DBDock is built for developers and teams who want dependable database operations without stitching tools together — whether you prefer a dashboard, a terminal, or both. The Cloud quickstart. The CLI quickstart. # Encryption key rotation Source: https://docs.dbdock.xyz/guides/key-rotation Safely rotate DBDock encryption keys without losing access to old backups. Encryption keys should rotate periodically — annually is a common cadence, more often if a key was potentially exposed. This guide walks through the rotation procedure. ## Why rotate * **Defense in depth** — if a key is compromised in the future, only post-rotation data is affected * **Compliance** — SOC 2 and similar frameworks expect periodic key rotation * **Departing team members** — if someone with key access leaves, rotate ## Important: losing access vs. rotation **Rotating a key does NOT automatically re-encrypt old backups.** Old backups were encrypted with the old key and remain decryptable only with the old key. Rotation means the *new* key is used going forward. If you want all backups to use the new key, you must re-encrypt them (see "Full re-encryption" below). ## Procedure — forward-only rotation Easiest and safest. Old backups keep their old key; new backups use the new key. ```bash theme={null} node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` Save the output somewhere secure (password manager, cloud KMS). Before you change anything, note down the old key and which backups it decrypts. You'll need it to restore any backup encrypted with it. **Do not discard the old key.** Move it to a secure archive — labelled with the date range it was active — not the trash. ```bash theme={null} DBDOCK_ENCRYPTION_SECRET= ``` If running in CI/CD or a secret manager, rotate it there. They cache the env at startup. `pm2 restart`, `kubectl rollout restart`, etc. Run a backup and a restore of that fresh backup: ```bash theme={null} npx dbdock backup npx dbdock restore # pick the one you just made ``` If both succeed, the new key is live. ## Full re-encryption If you want every backup to use the new key, do this after the forward-only rotation: Point DBDock at the **old** key temporarily, on a machine that can reach both the old backup storage and new backup storage. * Restore the backup to a temporary database * Switch DBDock to the new key * Run `dbdock backup` against the temporary database * Verify the new backup restores cleanly * Drop the temporary database * Delete the old backup ```bash theme={null} npx dbdock list --days 365 ``` All backups should show a timestamp after your rotation date. This is labour-intensive for large backup sets. For most teams, forward-only rotation + keeping the old key archived is sufficient. ## Restoring a backup encrypted with an old key Temporarily swap the env variable: ```bash theme={null} DBDOCK_ENCRYPTION_SECRET= npx dbdock restore ``` Pick the old backup and let it run. Put the new key back when done. ## Multi-key scenarios DBDock reads a single encryption key at a time. If you need truly multi-key support (e.g., different keys per environment, automatic failover), consider wrapping DBDock in your own script that sets the correct key based on metadata. ## Storing keys safely 1Password, Bitwarden, etc. Good for personal use and small teams. AWS KMS, GCP KMS, Azure Key Vault. Best for production — audit logs, rotation, IAM. Self-hosted, full-featured. Worth it if you're already running it. Using `git-crypt` or SOPS. OK for small teams with good ops hygiene. ## Checklist When rotating: * [ ] New key generated and saved in secure storage * [ ] Old key archived (not deleted) with its active date range * [ ] Env updated in all environments (prod, staging, CI) * [ ] Long-lived DBDock processes restarted * [ ] Smoke test passed (backup + restore with new key) * [ ] Team notified of the rotation date (for audit purposes) ## See also Overall security best practices. Full deployment checklist. # Production deployment checklist Source: https://docs.dbdock.xyz/guides/production-checklist Everything to verify before relying on DBDock in production. Before DBDock is responsible for backups you'd cry to lose, walk through this list. ## Setup * [ ] Database connection works (`dbdock test`) * [ ] Storage provider credentials work (`dbdock test`) * [ ] `dbdock.config.json` is committed to your repo * [ ] `.env` is in `.gitignore` and never committed * [ ] `DBDOCK_STRICT_MODE=true` is set in production ## Security * [ ] Encryption enabled (`"encryption": { "enabled": true }`) * [ ] `DBDOCK_ENCRYPTION_SECRET` is a 64-char hex key * [ ] The encryption key is stored in a secret manager (password manager, KMS), not just in `.env` * [ ] The encryption key is **not** stored in the same place as the backup destination * [ ] Storage bucket is private (block all public access) * [ ] Bucket has server-side encryption enabled * [ ] IAM user for DBDock has least-privilege permissions only * [ ] Bucket has versioning enabled (ransomware protection) ## Backups * [ ] Test backup completes successfully (`dbdock backup`) * [ ] Test restore completes successfully (`dbdock restore`) * [ ] Backup size looks right (not suspiciously small) * [ ] Restored database has the expected row counts ## Retention * [ ] Retention policy set (see [Retention strategies](/guides/retention-strategies)) * [ ] `minBackups` is non-zero so a misconfiguration doesn't wipe everything * [ ] `runAfterBackup: true` or a separate `dbdock cleanup` cron is scheduled * [ ] Storage cost is projected against your retention (cloud providers' pricing calculators) ## Scheduling * [ ] Backup schedule set (cron, Kubernetes CronJob, cloud scheduler) * [ ] Schedule runs at off-peak hours to avoid production impact * [ ] Schedule's machine/runner is monitored — if the runner dies, backups die with it ## Alerts * [ ] Slack or email alerts configured * [ ] Test alert delivered (`dbdock test`) * [ ] Alerts go to a channel that gets checked — not a dead channel * [ ] On-call has access to the alert channel ## Disaster recovery * [ ] Run a **full restore drill** — pick a recent backup and restore to a fresh DB * [ ] Document the restore procedure so anyone on the team can do it * [ ] Test restoring after losing access to the primary storage region (if multi-region) * [ ] Document the encryption key location and who has access ## Monitoring * [ ] Alert on backup failures (from DBDock alerts) * [ ] Alert on missing backups (something that tracks "last backup timestamp" and pages if it's too old) * [ ] Alert on storage quota — bucket size and growth rate * [ ] Log aggregation captures DBDock output (for forensics) ## Documentation * [ ] Runbook covers: "how do I take a manual backup", "how do I restore", "how do I add a schedule" * [ ] Runbook covers: "where is the encryption key", "who has access" * [ ] Runbook covers: "what do I do when an alert fires" * [ ] On-call docs reference the DBDock docs ## Compliance (if applicable) * [ ] Retention period meets your framework (SOC 2 typically 1 year+) * [ ] Access to backups is logged (cloud CloudTrail / audit logs) * [ ] Encryption algorithm is approved for your framework * [ ] Backups stored in an approved region * [ ] Data residency requirements met ## Ongoing * [ ] Quarterly restore drill scheduled * [ ] Annual key rotation scheduled (see [Key rotation](/guides/key-rotation)) * [ ] DBDock version kept up to date (`npm outdated`) ## Common mistakes ### "We have backups, we're fine" Backups that have never been restored aren't backups — they're files. Run a restore drill. You'll find at least one problem the first time. ### Storing the encryption key next to the backups If an attacker gets your S3 bucket, they shouldn't also get the key. Keep keys in a separate trust domain. ### No minBackups If `maxAgeDays: 30` and you stop backing up for 31 days, cleanup will delete *everything*. Set `minBackups` as insurance. ### Silent alert failures A broken SMTP password means no email alerts, but also no warning that alerts are broken. Have a separate liveness check — "did a backup happen in the last 26 hours?" ### Bucket policy lets the world read backups Even with encryption, having a public bucket is a data exposure risk. Explicitly block public access. ## See also Security deep dive. Choose a retention policy. Rotate the encryption key. Keep staging fresh from prod. # Retention strategies Source: https://docs.dbdock.xyz/guides/retention-strategies Recommended backup retention policies for different workloads. Backups accumulate. A retention policy decides what to keep and what to delete. This page walks through common patterns. ## The three knobs Every DBDock retention policy combines three numbers: | Field | What it does | | ------------ | -------------------------------------- | | `maxBackups` | Hard cap on total count — oldest first | | `maxAgeDays` | Delete anything older than N days | | `minBackups` | Safety net — never go below this count | The safety net wins: if rules say "delete everything" but you only have 3 backups and `minBackups: 5`, nothing is deleted. See [`dbdock cleanup`](/cli/cleanup) for the command that applies the policy. ## Pattern 1 — minimal (small side project) ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 14, "maxAgeDays": 14, "minBackups": 3, "runAfterBackup": true } } } ``` Two weeks of daily backups. If backups happen less than daily, keeps enough to recover from a recent failure. Cheap storage, minimal compliance. **Good for:** side projects, dev/staging databases, early-stage startups. ## Pattern 2 — standard production (daily backups) ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 90, "maxAgeDays": 90, "minBackups": 7, "runAfterBackup": true } } } ``` Three months of daily backups. Handles the common "oh no, this bug was introduced 6 weeks ago" scenario. **Good for:** most production Postgres setups without specific compliance needs. ## Pattern 3 — compliance (long retention) For SOC 2, HIPAA, or similar frameworks that require 1+ year retention. ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 400, "maxAgeDays": 400, "minBackups": 30, "runAfterBackup": true } } } ``` Daily backups for 13 months. Combines with S3/R2 lifecycle rules (move to Glacier after 30 days) to reduce cost: ```json theme={null} { "Rules": [ { "Id": "archive-old-dbdock-backups", "Status": "Enabled", "Filter": { "Prefix": "dbdock_backups/" }, "Transitions": [ { "Days": 30, "StorageClass": "GLACIER" } ] } ] } ``` **Good for:** regulated industries, enterprise deployments. ## Pattern 4 — hourly with tiered retention High-churn databases where 24h RPO isn't enough. Run backups hourly: ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 168, "maxAgeDays": 7, "minBackups": 12, "runAfterBackup": true } } } ``` 168 backups = 7 days × 24 hours. Combine with a second scheduler that keeps daily snapshots: ``` 0 * * * * cd /app && npx dbdock backup ``` Daily snapshots with longer retention require either: * A separate DBDock config that writes to a different storage prefix with longer `maxAgeDays` * Or manual promotion — copy a daily backup to a "long-term" prefix outside `dbdock_backups/` ## Pattern 5 — grandfather-father-son (classic) Not natively supported by DBDock's 3-knob policy, but achievable with external tooling: * **Son (daily):** 7 days * **Father (weekly):** 4 weeks * **Grandfather (monthly):** 12 months Implement by running three separate DBDock configs to three separate storage prefixes, each with its own retention. Or use a cloud lifecycle rule on top of a single prefix. ## Choosing values ### `maxBackups` vs `maxAgeDays` Both apply — the tighter one wins: * `maxBackups: 30`, `maxAgeDays: 30`, daily schedule → 30 backups (both match) * `maxBackups: 30`, `maxAgeDays: 365`, daily schedule → 30 backups (`maxBackups` wins) * `maxBackups: 365`, `maxAgeDays: 30`, hourly schedule → \~720 backups (`maxAgeDays` wins) Set both so one acts as a ceiling and the other as a floor. ### `minBackups` * Development: `3` * Staging: `5` * Production: `7` or higher Think of it as: "if everything went wrong and I stopped taking backups, how many days of history do I always want on hand?" ### `runAfterBackup` * `true` (default) — cleanup runs right after each successful backup. Keeps storage tidy automatically. * `false` — cleanup only runs when `dbdock cleanup` is invoked manually. Useful if you have a separate retention orchestration. ## Monitoring retention ```bash theme={null} npx dbdock list ``` Check the backup count and oldest date periodically to confirm retention is working. If you expect 30 backups and see 300, something is wrong with `runAfterBackup` or the cron. Even better, have your alerting check: ```bash theme={null} npx dbdock list --limit 1000 | wc -l ``` And alert if the count drifts outside expected bounds. ## See also Apply the retention policy. Pre-flight for prod deployment. # Refresh staging from production Source: https://docs.dbdock.xyz/guides/staging-refresh Keep staging databases current with production data using dbdock copydb. One of the most common DBDock workflows: overnight, pull production data into staging so the team starts each day with realistic data. ## The simple version ```bash theme={null} npx dbdock copydb "$PROD_URL" "$STAGING_URL" ``` That's it — `copydb` streams from source to target with no intermediate file. Confirm the prompt and DBDock takes care of the rest. ## Scheduled overnight refresh Create a cron job (or Kubernetes CronJob / GitHub Actions scheduled workflow): ``` 0 3 * * * /app/scripts/refresh-staging.sh >> /var/log/refresh.log 2>&1 ``` `refresh-staging.sh`: ```bash theme={null} #!/usr/bin/env bash set -euo pipefail export PROD_URL="${PROD_URL}" export STAGING_URL="${STAGING_URL}" echo "[$(date -u +%FT%TZ)] Starting staging refresh" # Drop and recreate the staging database to guarantee a clean slate psql "$STAGING_URL" -c "DROP DATABASE IF EXISTS myapp_staging;" psql "$STAGING_URL" -c "CREATE DATABASE myapp_staging;" # Copy production into the fresh staging database npx --yes dbdock copydb "$PROD_URL" "$STAGING_URL" --yes echo "[$(date -u +%FT%TZ)] Refresh complete" ``` ## Scrubbing sensitive data **Real user data in staging is a privacy/compliance risk.** If your production database has PII, health data, payment info, or any regulated data, you need to scrub it before developers touch it. The scrub-before-share pattern: ```bash theme={null} # 1. Copy prod to a "clean room" staging database npx dbdock copydb "$PROD_URL" "$CLEAN_ROOM_URL" # 2. Scrub the clean room psql "$CLEAN_ROOM_URL" <<'SQL' UPDATE users SET email = 'user' || id || '@example.invalid', phone = NULL, ssn = NULL; UPDATE payment_methods SET card_last4 = '0000'; DELETE FROM audit_logs WHERE created_at < now() - interval '90 days'; SQL # 3. Copy the scrubbed clean room to the developer-facing staging npx dbdock copydb "$CLEAN_ROOM_URL" "$STAGING_URL" # 4. Clean up the clean room psql "$CLEAN_ROOM_URL" -c "DROP DATABASE clean_room;" ``` ## Partial refresh (schema only) Want to keep staging's data but align its schema with production? ```bash theme={null} npx dbdock copydb --schema-only "$PROD_URL" "$STAGING_URL" ``` This copies DDL (tables, columns, indexes, constraints) but not rows. Useful for schema drift detection. ## Stale data detection Add a check that staging is recent: ```sql theme={null} -- In staging SELECT max(updated_at) FROM events; ``` If the max is more than 24 hours old, alert the team — the refresh job may be broken. ## Development workflow For individual developers who want to pull latest prod data into their local: ```bash theme={null} # Pull prod to local once npx dbdock copydb "$PROD_URL" "postgresql://localhost:5432/myapp" # Later, refresh from staging instead of prod (less load on prod) npx dbdock copydb "$STAGING_URL" "postgresql://localhost:5432/myapp" ``` ## Serverless Postgres hosts If your staging or production is on a serverless Postgres (Neon, Supabase pooler, PlanetScale Postgres), pass `--driver`: ```bash theme={null} npx dbdock copydb --driver "$NEON_URL" "$STAGING_URL" ``` See the [`copydb` reference](/cli/copydb) for details. ## See also Full command reference. Keep backup counts sane. # Changelog Source: https://docs.dbdock.xyz/help/changelog What's new in each DBDock release. Full changelog lives in the repository: [dbdock/dbdock CHANGELOG.md](https://github.com/dbdock/dbdock/blob/main/CHANGELOG.md). Below is a high-level summary of notable releases. ## 1.1.26 — Latest * `--driver` flag on `copydb` for serverless Postgres compatibility (Neon, Supabase pooler, PlanetScale Postgres) * Stricter TypeScript types across the codebase * Re-enabled `@typescript-eslint/no-explicit-any` — the codebase is now `any`-free * Open-source release: moved to `github.com/dbdock/dbdock`, added CONTRIBUTING/SECURITY/CHANGELOG, CI workflow ## 1.1.22 * Replaced `uuid` with `nanoid` for backup ID generation (smaller, URL-safe) * SMTP configuration handling improvements with optional chaining ## 1.1.17 * Support for environment-only configuration — no config file needed * `DBDOCK_DB_URL` / `DATABASE_URL` as first-class database configuration ## 1.1.15 * `copydb` command for direct database-to-database copies ## 1.1.11 * Custom webhook support * Improved environment variable handling ## 1.1.4 * Migration tool for moving legacy secrets from config to env (`dbdock migrate-config`) * Credential masking in logs ## 1.0.0 * First stable release * PostgreSQL backup and restore * Storage adapters: local, S3, R2, Cloudinary * AES-256-GCM encryption, zstd compression * Retention policies * Email and Slack alerts * Cron-based scheduling * Programmatic SDK ## Release notes on GitHub Each release has detailed notes and the diff since the previous version on GitHub: [github.com/dbdock/dbdock/releases](https://github.com/dbdock/dbdock/releases) ## Upgrading DBDock follows [semver](https://semver.org). Patch and minor updates are backwards-compatible. ### Check your version ```bash theme={null} dbdock --version ``` ### Update global install ```bash theme={null} npm update -g dbdock ``` ### Update project dependency ```bash theme={null} npm update dbdock ``` Or pin to a specific version: ```bash theme={null} npm install dbdock@1.1.26 ``` ## Breaking changes None to date — every 1.x release is backwards-compatible with 1.0. If a 2.0 release arrives with breaking changes, this page will document the migration path. # FAQ Source: https://docs.dbdock.xyz/help/faq Quick answers to common questions. ## Supported databases ### Which databases does DBDock support? DBDock supports **nine connection types**: PostgreSQL, MySQL, MariaDB, SQL Server, CockroachDB, Amazon Redshift, TimescaleDB, MongoDB, and Redis. | Capability | Engines | | --------------------------------- | ----------------------------------------------------------------------------------------------------- | | Backup, restore, same-engine copy | PostgreSQL family (PostgreSQL, CockroachDB, Redshift, TimescaleDB), MySQL, MariaDB, SQL Server, Redis | | Cross-database migration | MongoDB ↔ PostgreSQL only | | Connect and inspect | All nine | The PostgreSQL family uses `pg_dump` / `pg_restore`. MySQL and MariaDB use `mysqldump`. SQL Server uses `mssql-scripter` and `sqlcmd`. Redis uses a bundled worker that streams a binary DUMP/RESTORE format. MongoDB has **no native backup engine** in DBDock today. Use it for analysis and MongoDB ↔ PostgreSQL migration. ### Which Postgres versions are supported? Whatever your installed `pg_dump` supports — in practice Postgres 12+. Match the client tool version to your server version. ### Does DBDock support MySQL, MariaDB, SQL Server, or Redis backups? Yes. Backup, restore, and same-engine copy jobs work for MySQL, MariaDB, SQL Server, and Redis. Native client tools must be on your `PATH` (`mysqldump`, `mssql-scripter`, `sqlcmd`, etc.). ## General ### Is DBDock free? Yes — MIT licensed, free forever, self-hosted CLI. No vendor lock-in. The hosted dashboard at [dbdock.xyz](https://dbdock.xyz) has a free tier with managed storage included. ### Who's behind DBDock? Created by [Naheem Olaide](https://github.com/appdever01). Open-source project, contributions welcome on [GitHub](https://github.com/dbdock/dbdock). ### Is DBDock production-ready? Backup and restore pipelines are stable across PostgreSQL, MySQL, MariaDB, SQL Server, and Redis. Cross-database migration (MongoDB ↔ Postgres) is newer — run a dry run before production use. ### How is DBDock different from `pg_dump`? `pg_dump` is the engine for PostgreSQL-family databases. DBDock builds around it (and equivalent tools for other engines) with: * Storage adapters (local, S3, R2, Cloudinary) * Compression and encryption pipelines * Retention and scheduling * Restore UX with filtering (PostgreSQL family) * Cross-database migration (MongoDB ↔ Postgres) * Same-engine copy jobs for MySQL, MariaDB, SQL Server, and Redis Think of DBDock as the toolkit around your database dump tools. ### Is there a hosted DBDock? The CLI is self-hosted. The [DBDock web app](https://dbdock.xyz) adds a dashboard, managed storage, schedules, alerts, analytics, and billing tiers on top of the same engine layer. ### Is there a GUI? The hosted dashboard at [dbdock.xyz](https://dbdock.xyz) covers connections, backups, restores, copy jobs, migrations, schedules, and alerts. The CLI remains the option for scripts, CI, and fully self-hosted workflows. ## Installation ### Can I use DBDock without installing it? Yes — `npx dbdock ` works without a global install. ### Does DBDock need Node.js? Yes, Node 18 or later. If you can't install Node, a Docker image is the easiest workaround. ### What client tools do I need? At minimum, install the tools for the engines you use: * **PostgreSQL family** — `pg_dump`, `pg_restore`, `psql` * **MySQL / MariaDB** — `mysqldump`, `mysql` * **SQL Server** — `mssql-scripter`, `sqlcmd` * **Redis** — bundled worker (no extra install) * **MongoDB migration** — uses the `mongodb` driver at runtime Run `npx dbdock test` to validate your setup. ## Backup behavior ### How long does a backup take? Depends on database size, compression level, and network. Rough ballpark: * 100 MB DB, local storage: \~2–5 seconds * 1 GB DB, S3 us-east-1: \~30–60 seconds * 10 GB DB, S3 cross-region: \~5–10 minutes Run a test backup and measure for your setup. ### Can I back up a live production database? Yes — logical dumps use MVCC or engine equivalents so reads and writes continue. Expect slightly higher CPU during the dump and possible replication lag on replicas. Run during low-traffic windows when you can. ### Can I back up only some tables? PostgreSQL-family restores support selective restore from custom-format dumps. For partial backups at dump time, use engine flags directly (`pg_dump --table=...`, etc.) and upload the result yourself. Table-level backup in the CLI is on the [issue tracker](https://github.com/dbdock/dbdock/issues). ### Does DBDock support incremental backups? PostgreSQL logical dumps are full each time. For WAL-based incremental backup, use PostgreSQL's built-in WAL archiving separately. Cross-database **migration** supports incremental mode — see [Incremental migration](/migration/incremental). ## Restore ### Can I restore to a different database? Yes. In `dbdock restore`, choose "New Database Instance (Migrate)" and enter target connection details. Same-engine copy also works via `dbdock copydb`. See [`dbdock restore`](/cli/restore) and [`dbdock copydb`](/cli/copydb). ### Can I restore only specific tables? PostgreSQL custom-format dumps support selective restore through `pg_restore`. Other engines restore whole databases. Restore into a temporary database and extract what you need if partial restore isn't available for your engine. ### Can I preview a backup's contents? Not via DBDock currently for all engines. Restore to a temporary database and query it, or use native tools (`pg_restore --list` for PostgreSQL custom format). ## Storage ### Can I use multiple storage providers simultaneously? No — one active provider per config. Workarounds: * Run multiple configs (different `dbdock.config.json` paths via `DBDOCK_CONFIG_PATH`) * Sync primary storage to a secondary (S3 cross-region replication, rclone, etc.) ### How do I migrate backups between providers? DBDock doesn't have a built-in migrator. Options: * **AWS CLI / rclone** — copy files at the storage layer * **Manual** — `dbdock list`, download each, re-upload to the new provider * **Accept split history** — switch providers; new backups go to the new location ### Do backups work with S3 Object Lock? Yes. Object Lock is set at the bucket level; DBDock writes objects normally. Retention policies (`dbdock cleanup`) can't delete locked objects — coordinate both retention systems. ## Encryption ### What's the encryption algorithm? AES-256-GCM with a versioned backup format. Keys derive via PBKDF2-SHA512 with 100,000 iterations. Legacy backups use AES-256-CBC and still restore. ### Can I use multiple encryption keys? Not simultaneously. DBDock reads one key at a time. For rotating keys, see [Key rotation](/guides/key-rotation). ### Can I disable encryption for some backups? Yes — pass `--no-encrypt`: ```bash theme={null} npx dbdock backup --no-encrypt ``` ### Does encryption slow backups down? Measurably, but not dramatically. AES-256 on modern CPUs is fast (AES-NI). Most time is still network and compression. ## Migration ### Can I migrate MongoDB to PostgreSQL? Yes. See [Migration overview](/migration/overview). ### Can I migrate MySQL or SQL Server to PostgreSQL? Not as cross-engine migration. MySQL and SQL Server support **same-engine** backup, restore, and copy. Cross-engine migration is MongoDB ↔ PostgreSQL only today. ### What about live replication? DBDock migration is batch-oriented — not live replication. For CDC-style streaming, use Debezium, Airbyte, or similar. ## Development ### Does DBDock have a TypeScript SDK? Yes. All programmatic APIs have TypeScript definitions. See [SDK overview](/sdk/overview). ### Can I extend DBDock with custom storage providers? The four built-in providers (local, S3, R2, Cloudinary) are hardcoded. Adding a new provider means contributing a new adapter — [open a PR](https://github.com/dbdock/dbdock/pulls). ### Where do I report bugs? * [GitHub issues](https://github.com/dbdock/dbdock/issues) * Security issues privately via [security advisory](https://github.com/dbdock/dbdock/security/advisories/new) ## Still have questions? Ask the community. Common issues. # Troubleshooting Source: https://docs.dbdock.xyz/help/troubleshooting Common DBDock issues and how to fix them. **First step, always:** `npx dbdock test`. It validates your database, storage, encryption, and alert config in one shot. ## Installation issues ### `pg_dump`, `pg_restore`, or `psql` not found DBDock uses PostgreSQL's command-line tools. Install them: ```bash theme={null} brew install postgresql ``` ```bash theme={null} sudo apt-get update sudo apt-get install postgresql-client ``` ```bash theme={null} sudo dnf install postgresql ``` Install from [postgresql.org](https://www.postgresql.org/download/windows/) — choose "Command Line Tools" if you don't want the full server. Verify: `pg_dump --version` ### `EACCES` on `npm install -g dbdock` Don't use `sudo`. Configure npm's global prefix to a directory you own: ```bash theme={null} mkdir -p ~/.npm-global npm config set prefix '~/.npm-global' echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc source ~/.zshrc npm install -g dbdock ``` ## Configuration issues ### Secrets still in `dbdock.config.json` Migrate them to `.env`: ```bash theme={null} npx dbdock migrate-config ``` See [`dbdock migrate-config`](/cli/migrate-config). ### Strict mode failures If `DBDOCK_STRICT_MODE=true` and you see errors about secrets in config, run `migrate-config` — strict mode refuses any config file that contains secrets. ### Missing environment variables DBDock needs at minimum: * **Database** — either `DBDOCK_DB_URL` / `DATABASE_URL`, or `DBDOCK_DB_PASSWORD` (with connection details in the config file) * **Storage credentials** if using S3/R2/Cloudinary * **`DBDOCK_ENCRYPTION_SECRET`** if encryption is enabled Check your `.env` exists and contains the right variables. See the [configuration reference](/core/configuration#environment-variables-reference). ## Database connection errors ### `password authentication failed` * Your password is wrong or has been rotated * If using `DBDOCK_DB_URL`, password is URL-encoded — special characters like `@`, `#`, `/` must be percent-encoded ### `could not connect to server: Connection refused` * Postgres server isn't running on that host/port * Firewall blocks outbound connection (check security groups, network ACLs) * Test manually: `psql -h HOST -p PORT -U USER -d DBNAME` ### `connection timed out` * Remote server is unreachable * If on a cloud VPC, check security groups allow traffic from your runner * Increase timeout: not configurable in DBDock, use network/firewall fixes instead ### `.pgpass` not being used * File must be at `~/.pgpass` * File permissions must be exactly `0600`: `chmod 600 ~/.pgpass` * Format: `host:port:database:user:password` — no spaces ## Storage errors ### AWS S3 `DBDOCK_STORAGE_ACCESS_KEY` and `DBDOCK_STORAGE_SECRET_KEY` set in `.env`. Try `aws s3 ls s3://your-bucket` to test. Required: `s3:PutObject`, `s3:GetObject`, `s3:ListBucket`, `s3:DeleteObject`. Bucket name must match config exactly. Region must match the bucket's actual region. S3 rejects requests more than 15 min off. Check `date` on your machine vs `date` on a trusted server. ### Cloudflare R2 * Endpoint URL: `https://.r2.cloudflarestorage.com` (not `pub-.r2.dev`) * Account ID is in your Cloudflare dashboard sidebar * API token must have Object Read & Write scope * Region is always `auto` ### Cloudinary * `cloudName` in config must exactly match dashboard (case-sensitive) * API credentials are under Dashboard → Account Details * Free tier is 25 GB — check usage in dashboard ## Encryption key errors ### Invalid encryption key The key must be **exactly 64 hexadecimal characters** (0-9, a-f): ```bash theme={null} node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` Store in `.env` as `DBDOCK_ENCRYPTION_SECRET`. ### Restore fails with decryption error * Wrong key — old backups need the key they were encrypted with * See [Key rotation guide](/guides/key-rotation) for restoring backups encrypted with an old key If you've lost the encryption key and have no backup of the key itself, the encrypted data is **not recoverable**. This is by design. ## No backups found during restore ```bash theme={null} npx dbdock list ``` If `list` shows nothing: * Check files exist in the configured `path` * File permissions allow reading * Files follow pattern: `backup-*.sql` * Files are in the `dbdock_backups/` prefix * Correct bucket + region * Filenames match: `backup-*.sql` * Look in `dbdock_backups` folder in Media Library * Correct cloud name * Filenames match: `backup-*.sql` ## Alerts not delivering ### Email * Check spam folder first * Verify SMTP credentials (Gmail needs App Password, not account password) * Provider's activity/send logs (SendGrid, SES, Mailgun all have dashboards) * Run `npx dbdock test` to send a test ### Slack * Webhook URL still valid (recreate if deleted) * Channel still exists * App still installed in workspace ## Getting more help Still stuck? Ask the community. Report a bug or request a feature. When reporting issues, always include: * DBDock version (`dbdock --version`) * Node version (`node --version`) * OS * Output of `npx dbdock test` (redact any credentials before sharing) # DBDock Documentation Source: https://docs.dbdock.xyz/index DBDock is a database toolkit for PostgreSQL and MongoDB — backups, restores, database copies, and cross-database migrations. Use the open-source CLI, the managed cloud dashboard, or both, kept in sync. DBDock handles the database chores you'd rather not write scripts for: **backups, restores, database copies, scheduling, and cross-database migrations** — with encryption, compression, and multi-cloud storage built in. There are two ways to use it, and they work together: A hosted dashboard at [dbdock.xyz](https://dbdock.xyz). Connect a database, schedule encrypted backups, and manage everything from the browser — no infrastructure to run. An open-source, MIT-licensed command-line tool. Run backups and migrations locally or in CI, from a single `dbdock` command. **They're the same toolkit.** [Cloud Sync](/cloud-sync/overview) links a local CLI project to your cloud dashboard, so you can automate from the terminal and monitor from the browser. Only non-secret metadata leaves your machine — [see what syncs](/cloud-sync/data-handling). ## Pick your path Start with the [Cloud quickstart](/get-started/quickstart-cloud) — connect a database and take your first backup in the browser. Start with the [CLI quickstart](/get-started/quickstart) — install `dbdock` and back up a database in one command. Do either quickstart, then run `dbdock login` and `dbdock sync` to [link the two](/cloud-sync/overview). ## What you can do ```bash theme={null} npx dbdock backup # Encrypted, compressed backup npx dbdock restore # Interactive point-in-time restore npx dbdock copydb "src_url" "dst_url" # Clone a database, zero config npx dbdock migrate "mongo_url" "postgres_url" # Cross-database migration npx dbdock login && npx dbdock sync # Link this project to the cloud ``` ## Features at a glance PostgreSQL and MongoDB backups with AES-256-GCM encryption and zstd compression. Restore interactively or automate it. Clone prod → staging → local with a single command. No dump files to babysit. MongoDB ↔ PostgreSQL with automatic schema mapping, dry runs, and incremental syncs. Cron-based schedules that run in the cloud or from the CLI — with retries and run history. DBDock managed storage, or bring your own: AWS S3, Cloudflare R2, Cloudinary, local disk. Email, Slack, and webhooks for backup success, failure, and schedule events. Track database growth over time and build no-code admin dashboards from your data. Encryption by default, secrets kept in environment variables, and metadata-only cloud sync. ## Popular pages Link the CLI to your dashboard. How DBDock protects your data. Every command and flag. ## Get help * [Dashboard](https://dbdock.xyz) — the DBDock Cloud web app * [Troubleshooting](/help/troubleshooting) — common issues and fixes * [FAQ](/help/faq) — quick answers * [GitHub](https://github.com/dbdock/dbdock) — source, issues, and discussions # dbdock analyze Source: https://docs.dbdock.xyz/migration/analyze Scan a database and print its shape, types, and inconsistencies. ```bash theme={null} npx dbdock analyze ``` `analyze` reads the structure of a database — MongoDB or PostgreSQL — and reports what's inside. Use it before running a cross-database migration to understand what you're migrating. ## Examples ### Analyze MongoDB ```bash theme={null} npx dbdock analyze "mongodb://localhost:27017/myapp" ``` ### Analyze PostgreSQL ```bash theme={null} npx dbdock analyze "postgresql://user:pass@localhost:5432/myapp" ``` ## What it reports ### For MongoDB * Collection names and document counts * Field names per collection * Inferred types per field (with frequency if heterogeneous) * Nesting depth * Potential reference fields (`_id` patterns that look like foreign keys) * Index coverage ### For PostgreSQL * Table names and row counts * Column types and nullability * Primary and foreign keys * Indexes * Sequence/identity columns ### Sample output (MongoDB) ``` Database: myapp (mongodb://localhost:27017) Collections: 4 ┌──────────────┬──────────┬────────┬─────────┐ │ Collection │ Documents│ Fields │ Indexes │ ├──────────────┼──────────┼────────┼─────────┤ │ users │ 12,450 │ 8 │ 3 │ │ orders │ 48,910 │ 12 │ 5 │ │ products │ 820 │ 14 │ 2 │ │ reviews │ 3,180 │ 6 │ 1 │ └──────────────┴──────────┴────────┴─────────┘ users: _id ObjectId (unique) email String (unique, 12,450 values) name String age Number (99.2% Int, 0.8% Double) ⚠️ mixed types created_at Date metadata Object (nested, depth 2) deleted_at Date|null tags Array ⚠️ Inconsistencies found: • users.age has mixed numeric types (Int and Double) • orders.total has 12 documents missing the field • products.price has 3 documents with type String instead of Number ``` ## What to do with the output Mixed types and missing fields cause migration errors. Fix them in the source first when you can. Decide which nested objects to flatten vs keep as jsonb. Huge collections need smaller batches (see `--batch-size`). Save the proposed mapping with `dbdock migrate --export-config`. ## Read-only `analyze` only reads — it doesn't modify the source database. Safe to run against production. ## See also Run the actual migration. How DBDock maps types. # Dry runs & validation Source: https://docs.dbdock.xyz/migration/dry-run Validate a migration plan against a temporary schema before committing. `--dry-run` runs the full migration into a temporary schema (or collection prefix) so you can inspect the result before touching production. Nothing is written to your real target. ## Basic usage ```bash theme={null} npx dbdock migrate "$SRC" "$DST" --dry-run ``` ## What changes in dry-run mode ### MongoDB → PostgreSQL A dry run creates a schema named `dbdock_dryrun_` and migrates into tables there: ``` source: mongodb://.../myapp target: postgresql://.../myapp.dbdock_dryrun_20260416_080000.users dbdock_dryrun_20260416_080000.orders ... ``` Query those tables to verify the mapping. When you're satisfied, drop the schema: ```sql theme={null} DROP SCHEMA dbdock_dryrun_20260416_080000 CASCADE; ``` ### PostgreSQL → MongoDB A dry run creates collections prefixed with `dbdock_dryrun__`: ``` dbdock_dryrun_20260416_080000_users dbdock_dryrun_20260416_080000_orders ``` Drop them when done: ```javascript theme={null} db.getCollectionNames() .filter(n => n.startsWith('dbdock_dryrun_')) .forEach(n => db[n].drop()) ``` ## What to check in a dry run Verify every document/row made it: `SELECT count(*) FROM dryrun.users;` vs. the source count. Spot-check sample rows. Dates, nulls, and numbers are the most common sources of trouble. Look at `_migration_errors` — any skipped rows? Run your most important queries against the dry-run schema to confirm the indexes are right. ## Size of the dry run Dry runs migrate the full dataset by default, which is ideal for validation but slow on huge databases. To speed things up, use `--batch-size` and run against a reduced source if possible. DBDock doesn't have a `--sample` flag yet — open an issue on [GitHub](https://github.com/dbdock/dbdock/issues) if you need one. ## Production checklist after a successful dry run Before running the real migration: 1. ✅ Row counts match 2. ✅ Indexes created match expectations 3. ✅ Sample queries return correct results 4. ✅ Error table is empty (or errors are acceptable) 5. ✅ Target database has enough disk space 6. ✅ Team is informed (migrations can lock tables briefly) 7. ✅ You have a rollback plan (usually: drop the target schema) ## Cleaning up dry-run artifacts DBDock doesn't auto-drop dry-run schemas so you can inspect them. Drop them manually once done to reclaim space. ## See also Run the real migration. Pull only new/changed rows. # Incremental migration Source: https://docs.dbdock.xyz/migration/incremental Pull only new or changed data after an initial migration. Once you've done an initial migration, you usually want to keep the target in sync with the source as new data arrives. `--incremental` lets you pull only data newer than a cutoff. ## Basic usage ```bash theme={null} npx dbdock migrate "$SRC" "$DST" --incremental --since "2026-04-01T00:00:00Z" ``` `--since` is the cutoff — DBDock ignores anything older than this timestamp. ## How "changed" is determined DBDock looks for timestamp fields on each source table/collection: * MongoDB: `updated_at`, `createdAt`, or the `ObjectId` embedded timestamp * PostgreSQL: `updated_at`, `created_at`, or any `timestamptz` column named `*_at` If DBDock can't find a suitable field, it falls back to insert-only mode (new rows only, updates are missed). ## Recommended pattern ```bash theme={null} npx dbdock migrate "$SRC" "$DST" --export-config ./migration.json ``` Record the timestamp you finished — you'll use it as the next `--since`. ```bash theme={null} echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .dbdock-last-sync ``` ```bash theme={null} LAST=$(cat .dbdock-last-sync) npx dbdock migrate "$SRC" "$DST" --config ./migration.json --incremental --since "$LAST" date -u +%Y-%m-%dT%H:%M:%SZ > .dbdock-last-sync ``` Run the incremental sync hourly or daily depending on how fresh the target needs to be. ## Caveats ### Deletes aren't detected Incremental migration pulls inserts and updates. **Deletes in the source are not reflected in the target.** If you need full mirroring including deletes: * Do periodic full re-migrations (e.g., weekly full + hourly incremental) * Or use a dedicated CDC tool (Debezium, etc.) if the use case is live replication ### Clock drift `--since` uses the source database's timestamps. If source and target clocks drift, you may miss rows or duplicate some. Prefer timestamps from the source over wall-clock times from the runner. ### Primary keys must be stable Incremental updates rely on matching rows between source and target. If IDs change or are regenerated on each sync, updates will behave as inserts and duplicates will appear. ## Use cases Gradual migration — apps still write to Mongo, analytics queries hit Postgres. Keep a Postgres reporting database fresh from the MongoDB primary. Daily pull of new prod data into a staging DB. Keep an out-of-region mirror updated regularly. ## When NOT to use incremental * **Schema changed in the source.** Incremental mode assumes the schema is stable. For schema changes, do a full migration. * **You need strong consistency.** Incremental has a window where source ≠ target. For financial/compliance work, use transactional replication. * **Write throughput is very high.** Incremental can't keep up past a certain write rate. Use dedicated CDC. ## See also Full migration command. Validate before running. # dbdock migrate Source: https://docs.dbdock.xyz/migration/migrate Migrate data between MongoDB and PostgreSQL in either direction. ```bash theme={null} npx dbdock migrate [options] ``` `migrate` is the main cross-database migration command. DBDock analyzes the source, generates a schema mapping, shows it to you, and waits for confirmation before touching anything. Run [`dbdock analyze`](/migration/analyze) on the source first. It's read-only and tells you what you're about to migrate. ## Examples ### MongoDB → PostgreSQL ```bash theme={null} npx dbdock migrate \ "mongodb://localhost:27017/myapp" \ "postgresql://user:pass@localhost:5432/myapp" ``` ### PostgreSQL → MongoDB ```bash theme={null} npx dbdock migrate \ "postgresql://user:pass@localhost:5432/myapp" \ "mongodb://localhost:27017/myapp" ``` ## Options | Option | Description | | ------------------------ | --------------------------------------------------------------- | | `--dry-run` | Run against a temporary schema/collection prefix for validation | | `--incremental` | Only migrate new/changed data (needs `--since`) | | `--since ` | Cutoff date for incremental (ISO format) | | `--config ` | Use a saved migration config file | | `--export-config ` | Export the generated plan to a config file | | `--batch-size ` | Documents per batch (default `1000`) | | `--max-depth ` | Max nesting depth before jsonb (default `2`) | ## The confirmation flow ``` Analyzing source... Collections: 4 Documents: 65,360 Size: 142.8 MB Generating schema mapping... Proposed mapping: users (12,450 docs) → public.users (8 columns) orders (48,910 docs) → public.orders (12 columns + 2 fk) products (820 docs) → public.products (14 columns) reviews (3,180 docs) → public.reviews (6 columns + 1 fk) Estimated duration: 3-5 minutes ? Proceed with migration? (y/N) ``` ## What happens under the hood Validates credentials and reachability. Same logic as `dbdock analyze` — types, nesting, inconsistencies. Proposes target schema based on source shape and `--max-depth`. Scans for fields that look like references between collections/tables. Nothing is written yet. You see the full plan and confirm. Creates tables/collections. Idempotent — skips existing ones. Streams data in configurable batches. Progress bar shows rate and ETA. Failed rows go to `_migration_errors` with the error message. Summary: rows migrated, rows failed, duration. ## Reusing a mapping Generate and save the plan once: ```bash theme={null} npx dbdock migrate "$MONGO" "$PG" --export-config ./my-migration.json ``` Edit the file to customize the schema. Then: ```bash theme={null} npx dbdock migrate "$MONGO" "$PG" --config ./my-migration.json ``` Useful when you want the same migration to run in CI or against multiple environments. ## Tuning ### Large collections If a collection has millions of documents, lower the batch size to reduce memory and increase the commit frequency: ```bash theme={null} npx dbdock migrate "$MONGO" "$PG" --batch-size 500 ``` ### Deeply nested documents If your documents have complex nesting you don't want flattened, increase `--max-depth` — but past depth 2 or 3, you're usually better off with `jsonb`: ```bash theme={null} npx dbdock migrate "$MONGO" "$PG" --max-depth 1 ``` Anything beyond depth 1 stays as `jsonb` — usually the right default. ## See also Validate before committing. Type conversion details. Pull only new/changed data. # Migration overview Source: https://docs.dbdock.xyz/migration/overview Cross-database migration between MongoDB and PostgreSQL. DBDock can move data between **MongoDB and PostgreSQL** in either direction. It's designed for the case where you've outgrown MongoDB and want to land on Postgres (or vice versa) — not as a live replication tool. ## What gets migrated MongoDB collections → Postgres tables (or the reverse). Field types inferred from the source. Every document/row streamed in configurable batches. Best-effort detection of relationships to set up foreign keys. Failed rows are collected in a `_migration_errors` table/collection for review. ## Workflow Scan the source database to understand shape, types, and reference patterns. ```bash theme={null} npx dbdock analyze "mongodb://localhost:27017/myapp" ``` See [dbdock analyze](/migration/analyze). DBDock generates a schema mapping proposal you can review and customize. See [Schema mapping](/migration/schema-mapping). Validate the mapping against a temporary schema — no production writes. ```bash theme={null} npx dbdock migrate "$MONGO_URL" "$POSTGRES_URL" --dry-run ``` See [Dry runs](/migration/dry-run). Execute against the real target with your confirmation. ```bash theme={null} npx dbdock migrate "$MONGO_URL" "$POSTGRES_URL" ``` See [dbdock migrate](/migration/migrate). Run incremental migrations to pull only new/changed data. ```bash theme={null} npx dbdock migrate "$MONGO_URL" "$POSTGRES_URL" --incremental --since 2026-04-01 ``` See [Incremental migration](/migration/incremental). ## Directions ### MongoDB → PostgreSQL The most common direction. DBDock: * Flattens nested documents up to a configurable depth (default: 2 levels) * Stores deeper nesting as `jsonb` columns * Infers column types from observed values * Creates indexes for commonly-queried fields ### PostgreSQL → MongoDB Also supported. DBDock: * Maps tables to collections * Converts rows to documents, preserving column types * Optionally embeds related rows (one-to-many) into parent documents * Translates Postgres JSON/JSONB columns to native MongoDB documents ## Core principles 1. **Nothing runs without confirmation.** Every migration shows you the plan and waits for you to approve it. 2. **Errors don't halt the migration.** Failed rows go to `_migration_errors` so you can address them post-hoc without redoing the whole thing. 3. **Idempotent where possible.** Re-running a migration with the same config reuses existing tables rather than duplicating. 4. **You own the schema.** The generated mapping is a *proposal* — save it, edit it, commit it. ## See also Understand the source first. The migration command itself. How MongoDB types become Postgres types. Validate without touching production. # Schema mapping Source: https://docs.dbdock.xyz/migration/schema-mapping How DBDock translates types between MongoDB and PostgreSQL. Cross-database migration requires a type system translation. This page documents exactly how DBDock maps types in both directions. ## MongoDB → PostgreSQL ### Scalar types | BSON type | Postgres type | Notes | | ---------------------- | ------------------------------- | ------------------------------------------------------------------- | | `ObjectId` | `uuid` or `text` | Stored as hex string. Use `uuid` if you plan to keep the ID format. | | `String` | `text` | Length-agnostic. Use `varchar(n)` if you need a limit. | | `Int`, `Long` | `bigint` | Safe default for JS numeric ranges. | | `Double`, `Decimal128` | `double precision` or `numeric` | `numeric` preserves exact precision. | | `Boolean` | `boolean` | Direct map. | | `Date` | `timestamptz` | Always stored as UTC. | | `Binary` | `bytea` | Binary data. | | `null` | `NULL` | Column must be nullable. | ### Container types | BSON type | Postgres type | Notes | | ----------------- | --------------------------------- | ------------------------------------------------------------- | | `Object` (nested) | Flattened columns *or* `jsonb` | Depth ≤ `--max-depth` → flatten; deeper → jsonb. | | `Array` | `T[]` (native array) *or* `jsonb` | Homogeneous arrays of scalars → native array; mixed → jsonb. | | `Array` | `jsonb` | Always jsonb — one-to-many relationships aren't auto-derived. | ### Mixed types If a field has multiple types across documents (e.g., 99% `Int`, 1% `Double`), DBDock picks the "widest" compatible Postgres type. You'll see a warning: ``` ⚠️ users.age: mixed Int/Double → chose double precision ``` You can override this by editing the exported config file. ### Example MongoDB: ```json theme={null} { "_id": ObjectId("..."), "email": "alice@example.com", "profile": { "name": "Alice", "avatar_url": "https://..." }, "tags": ["admin", "beta"], "metadata": { "deep": { "nested": { "value": 1 } } } } ``` Postgres (with `--max-depth 2`): ```sql theme={null} CREATE TABLE users ( id uuid PRIMARY KEY, email text UNIQUE NOT NULL, profile_name text, profile_avatar_url text, tags text[], metadata jsonb -- deep nesting preserved as JSON ); ``` ## PostgreSQL → MongoDB ### Scalar types | Postgres type | BSON type | Notes | | -------------------------- | ------------------------ | --------------------------------------------- | | `uuid` | `String` | UUID as lowercase hex string. | | `text`, `varchar` | `String` | Direct map. | | `integer`, `bigint` | `Int` / `Long` | `bigint` may need `Long` on 32-bit platforms. | | `numeric`, `decimal` | `Decimal128` | Exact precision preserved. | | `real`, `double precision` | `Double` | IEEE 754 mapping. | | `boolean` | `Boolean` | Direct map. | | `date` | `Date` (at midnight UTC) | Date-only types lose time component. | | `timestamp`, `timestamptz` | `Date` | Stored as UTC. | | `bytea` | `Binary` | Direct map. | | `jsonb`, `json` | Native document | Parsed into MongoDB object. | ### Container types | Postgres type | BSON type | Notes | | --------------------- | -------------------------- | ---------------------------------- | | `T[]` (array) | `Array` | Element types mapped individually. | | Foreign key relations | Option: embed or reference | See below. | ### Relationships DBDock can optionally embed one-to-many relationships into parent documents: * **Reference mode** (default): stores the FK as-is, creates separate collections. * **Embed mode**: pulls child rows into a nested array on the parent document. Configure per-table in the exported config file. ### Example Postgres: ```sql theme={null} CREATE TABLE users ( id uuid PRIMARY KEY, email text UNIQUE ); CREATE TABLE posts ( id uuid PRIMARY KEY, user_id uuid REFERENCES users(id), title text, body text ); ``` MongoDB (reference mode): ```javascript theme={null} // users collection { _id: "...", email: "alice@example.com" } // posts collection { _id: "...", user_id: "...", title: "...", body: "..." } ``` MongoDB (embed mode): ```javascript theme={null} // users collection (posts embedded) { _id: "...", email: "alice@example.com", posts: [ { _id: "...", title: "...", body: "..." } ] } ``` ## Customizing the mapping Export the generated plan: ```bash theme={null} npx dbdock migrate "$SRC" "$DST" --export-config ./migration.json ``` Edit the file — change column types, rename fields, flag embeds, skip collections. Then run with the custom config: ```bash theme={null} npx dbdock migrate "$SRC" "$DST" --config ./migration.json ``` Commit the config file to git so your team uses the same mapping. # Alerts (SDK) Source: https://docs.dbdock.xyz/sdk/alerts Send backup notifications programmatically. Alerts fire automatically when `createBackup()` completes — you don't have to do anything. This page covers how to customize or trigger alerts manually. ## Automatic alerts ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); // Alerts fire automatically based on dbdock.config.json const result = await backups.createBackup({ compress: true, encrypt: true }); ``` Provided the `alerts` section of your config is enabled, success and failure notifications go out after each backup. ## Manual alerts For custom events (not tied to a DBDock backup operation), use `AlertService`: ```javascript theme={null} const { createDBDock, AlertService } = require('dbdock'); const dbdock = await createDBDock(); const alerts = dbdock.get(AlertService); await alerts.sendSuccess({ database: 'myapp', backupId: 'custom-2026-04-17-001', size: 45_000_000, duration: 8_500, }); ``` ## Methods ### `sendSuccess(details)` ```typescript theme={null} interface SuccessDetails { database: string; backupId: string; size: number; compressedSize?: number; duration: number; storageKey?: string; encrypted?: boolean; } ``` ### `sendFailure(details)` ```typescript theme={null} interface FailureDetails { database: string; error: Error | string; context?: Record; } ``` ### `sendTest()` Sends a test notification to all configured channels. Same as `npx dbdock test`. ## Controlling channel delivery Alerts go to every enabled channel. To send to only one channel, configure your `dbdock.config.json` to enable only that channel: ```json theme={null} { "alerts": { "slack": { "enabled": true }, "email": { "enabled": false } } } ``` Or programmatically toggle by reloading config per-environment. ## Custom alert content If the built-in alert content doesn't fit your needs, use your own alerting code and disable DBDock's alerts: ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); const dbdock = await createDBDock(); // dbdock.config.json has alerts disabled const backups = dbdock.get(BackupService); try { const result = await backups.createBackup({ compress: true, encrypt: true }); await myCustomAlert.success({ text: `Backup ${result.metadata.id} OK`, blocks: [/* whatever format your alerting system uses */], }); } catch (err) { await myCustomAlert.failure({ text: `Backup failed: ${err.message}`, }); } ``` This gives you full control at the cost of reimplementing the built-in content. ## Reliability notes * Alert delivery is **best-effort** — network errors don't fail the backup * Alerts are sent **after** the backup completes, so a failure during delivery doesn't delete the backup * For critical alerting, use a dedicated alerting service (PagerDuty, Opsgenie) fronted by a webhook — see [Custom webhooks](/alerts/webhooks) ## See also Available channels. Integrate with any HTTP endpoint. # Creating backups Source: https://docs.dbdock.xyz/sdk/creating-backups Create database backups programmatically with BackupService. ## Basic usage ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); async function createBackup() { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); const result = await backups.createBackup({ format: 'custom', compress: true, encrypt: true, }); console.log(`Backup created: ${result.metadata.id}`); console.log(`Size: ${result.metadata.formattedSize}`); console.log(`Path: ${result.storageKey}`); return result; } ``` ## Options | Option | Type | Default | Description | | ---------- | --------------------------------------------- | ----------- | ------------------------ | | `format` | `'custom' \| 'plain' \| 'directory' \| 'tar'` | from config | PostgreSQL backup format | | `compress` | `boolean` | from config | Apply zstd compression | | `encrypt` | `boolean` | from config | AES-256-GCM encryption | | `type` | `'full' \| 'schema' \| 'data'` | `'full'` | What to back up | All options default to the values in `dbdock.config.json`. Pass only the ones you want to override. ## Result shape ```typescript theme={null} interface BackupResult { metadata: BackupMetadata; storageKey: string; } interface BackupMetadata { id: string; database: string; startTime: Date; endTime: Date; duration: number; // ms size: number; // original bytes compressedSize: number; // compressed bytes formattedSize: string; // e.g. "45.23 MB" format: 'custom' | 'plain' | 'directory' | 'tar'; compression: { enabled: boolean; level?: number }; encryption: { enabled: boolean; algorithm?: string } | null; storageKey: string; } ``` ## Examples ### Schema-only backup ```javascript theme={null} await backups.createBackup({ type: 'schema' }); ``` Captures DDL (tables, indexes, constraints) but not data. Tiny files — good for tracking schema evolution. ### Data-only backup ```javascript theme={null} await backups.createBackup({ type: 'data' }); ``` Captures rows without DDL. Useful when you're restoring into a database that already has the schema. ### Plain SQL backup ```javascript theme={null} await backups.createBackup({ format: 'plain', compress: false }); ``` Human-readable SQL you can `grep`, inspect, or feed to `psql`. Usually much larger than `custom` format. ### Maximum compression for archival ```javascript theme={null} await backups.createBackup({ compress: true, compressionLevel: 11 }); ``` Slower to create but up to 20-30% smaller than the default level 6. Worth it for long-term retention. ### One-off unencrypted backup ```javascript theme={null} await backups.createBackup({ encrypt: false }); ``` Overrides the config's encryption setting for this single backup. ## Error handling ```javascript theme={null} try { const result = await backups.createBackup({ compress: true }); } catch (err) { if (err.code === 'DATABASE_CONNECTION_FAILED') { // handle connection errors specifically } console.error('Backup failed:', err.message); } ``` Errors from `createBackup` are standard `Error` instances with a `.code` property for structured handling. ## Alerts are automatic If alerts are configured in `dbdock.config.json`, they fire after `createBackup` — success or failure. You don't need to do anything extra. See [SDK → alerts](/sdk/alerts) if you want to send alerts manually. ## Performance tips ### Large databases Stream the output — which DBDock does by default — so you never buffer the whole dump. Avoid calling `createBackup` concurrently against the same database; PostgreSQL will serialize the dumps anyway and you'll waste resources. ### Remote databases with slow links Run the backup process on a machine *near* the database, not near your storage. The dump is usually 2-10x larger than the compressed/encrypted output, so it's cheaper to dump locally and upload than to dump across the internet. ### Monitoring Measure `result.metadata.duration` and alert if it drifts. Backup duration is a good proxy for database health. ## See also Query the backup history. Run on a schedule. Programmatic alerts. # Listing backups Source: https://docs.dbdock.xyz/sdk/listing-backups Query backup history programmatically. ## List all backups ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); async function listAll() { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); const list = await backups.listBackups(); for (const backup of list) { console.log(`${backup.id} (${backup.formattedSize}, ${backup.startTime})`); } } ``` `listBackups()` returns all backups from the configured storage provider, sorted newest first. ## Shape of each entry ```typescript theme={null} interface BackupSummary { id: string; storageKey: string; database: string; startTime: Date; endTime: Date; duration: number; size: number; compressedSize: number; formattedSize: string; encrypted: boolean; compressed: boolean; format: 'custom' | 'plain' | 'directory' | 'tar'; } ``` ## Get metadata for one backup ```javascript theme={null} const metadata = await backups.getBackupMetadata('backup-2026-04-16-08-00-00-abc123'); if (!metadata) { console.log('Backup not found'); } else { console.log('Size:', metadata.formattedSize); console.log('Encrypted:', metadata.encryption?.enabled); } ``` Returns `null` if the backup doesn't exist. ## Filtering `listBackups()` returns everything. Filter in JavaScript: ```javascript theme={null} const all = await backups.listBackups(); // Last 7 days const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); const recent = all.filter(b => b.startTime > weekAgo); // Only encrypted const encrypted = all.filter(b => b.encrypted); // Search by substring in ID const preDeploy = all.filter(b => b.id.includes('pre-deploy')); ``` For large backup sets, this is an in-memory filter after fetching — for thousands of backups you may want to paginate at the storage layer (future API). ## Sample: find the most recent successful backup ```javascript theme={null} async function getLatest() { const list = await backups.listBackups(); if (list.length === 0) return null; return list[0]; // already sorted newest-first } ``` ## Sample: report backup health ```javascript theme={null} async function healthReport() { const list = await backups.listBackups(); if (list.length === 0) { return { status: 'critical', reason: 'no backups exist' }; } const latest = list[0]; const hoursAgo = (Date.now() - latest.startTime.getTime()) / 3_600_000; if (hoursAgo > 30) { return { status: 'critical', reason: `latest backup is ${hoursAgo.toFixed(1)}h old` }; } if (list.length < 3) { return { status: 'warning', reason: 'fewer than 3 backups' }; } return { status: 'ok', backups: list.length, latestAgeHours: hoursAgo }; } ``` Wire this into your app's `/health` endpoint or cron-driven monitoring. ## See also Create new backups. CLI equivalent. # SDK overview Source: https://docs.dbdock.xyz/sdk/overview Use DBDock programmatically in your Node.js app. Everything the CLI does, you can do from code. DBDock exports a small NestJS-based module that works with any Node.js backend — you don't need to understand NestJS to use it. ## Install ```bash theme={null} npm install dbdock ``` ## The one pattern to learn ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); async function main() { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); const result = await backups.createBackup({ compress: true, encrypt: true, }); console.log('Backup created:', result.metadata.id); } main().catch(console.error); ``` Three steps: 1. `await createDBDock()` — initializes DBDock (reads `dbdock.config.json` and env vars) 2. `dbdock.get(ServiceClass)` — fetches the service you need 3. Call methods on the service ## Available services Create backups, list backups, get metadata. Direct access to the storage adapter (advanced). Encrypt/decrypt arbitrary data (advanced). Send notifications programmatically. ## TypeScript support DBDock ships full type definitions. In TypeScript: ```typescript theme={null} import { createDBDock, BackupService, type BackupMetadata } from 'dbdock'; async function main(): Promise { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); const result = await backups.createBackup({ compress: true, encrypt: true, }); const metadata: BackupMetadata = result.metadata; console.log(metadata.id); } ``` ## Configuration The SDK reads from the same sources as the CLI: 1. `dbdock.config.json` (path controlled by `DBDOCK_CONFIG_PATH`) 2. Environment variables (`.env` and `.env.local`) 3. Environment-only if no config file exists No separate SDK configuration needed. ## Lifecycle `createDBDock()` returns a context. Internally it holds connections and caches. If you're running a long-lived process, create it once and reuse it: ```javascript theme={null} const dbdock = await createDBDock(); // once at startup const backups = dbdock.get(BackupService); // use `backups` across many backup operations ``` If you're running in a short-lived context (CLI script, Lambda), creating per-invocation is fine. ## What's supported programmatically | Operation | CLI | SDK | | ------------------- | --- | -------------------- | | Create backup | ✅ | ✅ | | List backups | ✅ | ✅ | | Get backup metadata | ✅ | ✅ | | Delete backup | ✅ | ❌ (CLI only for now) | | Restore backup | ✅ | ❌ (CLI only for now) | | Cleanup (retention) | ✅ | ✅ | | Send alerts | ✅ | ✅ | | Cross-DB migration | ✅ | ❌ (CLI only) | | copydb | ✅ | ❌ (CLI only) | Restore and delete programmatic APIs are planned — follow [dbdock/dbdock#issues](https://github.com/dbdock/dbdock/issues) for updates. ## See also Full API for `BackupService.createBackup()`. Query the backup history. Build a scheduler with `node-cron`. Use the alert system from code. # Scheduling backups (SDK) Source: https://docs.dbdock.xyz/sdk/scheduling Build a scheduled backup runner with node-cron. DBDock doesn't ship its own daemon — pair the SDK with [`node-cron`](https://www.npmjs.com/package/node-cron) for programmatic scheduling. ## Install ```bash theme={null} npm install node-cron npm install --save-dev @types/node-cron # TypeScript ``` ## Minimal scheduler ```javascript theme={null} const { createDBDock, BackupService } = require('dbdock'); const cron = require('node-cron'); async function main() { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); cron.schedule('0 2 * * *', async () => { try { const result = await backups.createBackup({ compress: true, encrypt: true, }); console.log(`Backup ${result.metadata.id} completed`); } catch (err) { console.error('Backup failed:', err); } }); console.log('Scheduler started — daily backups at 02:00'); } main(); ``` Keep this process alive with PM2, systemd, or Docker. ## TypeScript version ```typescript theme={null} import { createDBDock, BackupService, type BackupResult } from 'dbdock'; import * as cron from 'node-cron'; async function startScheduler(): Promise { const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); cron.schedule('0 2 * * *', async () => { try { const result: BackupResult = await backups.createBackup({ compress: true, encrypt: true, }); console.log(`✅ ${result.metadata.id} (${result.metadata.formattedSize})`); } catch (err) { console.error('❌ Backup failed:', err); } }); } startScheduler().catch(console.error); ``` ## Reading schedules from config If you want to read schedules defined via `dbdock schedule`, load them from `dbdock.config.json`: ```javascript theme={null} const fs = require('fs'); const { createDBDock, BackupService } = require('dbdock'); const cron = require('node-cron'); async function main() { const config = JSON.parse(fs.readFileSync('dbdock.config.json', 'utf8')); const dbdock = await createDBDock(); const backups = dbdock.get(BackupService); for (const schedule of config.schedules ?? []) { if (!schedule.enabled) continue; cron.schedule(schedule.cron, async () => { console.log(`[${schedule.name}] Running backup`); try { await backups.createBackup({ compress: true, encrypt: true }); } catch (err) { console.error(`[${schedule.name}] Failed:`, err); } }); console.log(`Registered: ${schedule.name} (${schedule.cron})`); } } main(); ``` ## Running alongside your app Embed the scheduler in your existing Node.js service — no separate process needed: ```javascript theme={null} // server.ts import express from 'express'; import { startBackupScheduler } from './backup-scheduler'; const app = express(); // ... routes ... app.listen(3000, async () => { await startBackupScheduler(); console.log('Server + scheduler running'); }); ``` Downside: if your app restarts (deploy, crash), scheduled backups may be missed during the restart window. For mission-critical backups, use a separate process or cloud scheduler instead. ## Multiple schedules ```javascript theme={null} cron.schedule('0 * * * *', async () => { await backups.createBackup({ type: 'data', compress: true }); // hourly data-only }); cron.schedule('0 2 * * *', async () => { await backups.createBackup({ type: 'full', compress: true, encrypt: true }); // daily full }); cron.schedule('0 0 * * 0', async () => { await backups.createBackup({ type: 'full', compressionLevel: 11 }); // weekly archival }); ``` Mix frequencies and formats for a tiered backup strategy. ## Graceful shutdown ```javascript theme={null} const scheduled = cron.schedule('0 2 * * *', async () => { /* ... */ }); process.on('SIGTERM', () => { scheduled.stop(); process.exit(0); }); ``` Without this, a scheduled job mid-execution gets killed along with the process. ## See also All scheduling options compared. `BackupService.createBackup()` details. # Cloud Security Source: https://docs.dbdock.xyz/security/cloud How DBDock Cloud secures your data — OAuth sign-in, credentials encrypted at rest, per-account isolation, encrypted backups, scoped MCP access, and metadata-only CLI sync. DBDock Cloud stores database credentials and runs jobs on your behalf, so it's built to keep each account's data private and its secrets protected. ## Sign-in DBDock Cloud uses **OAuth** — there's no password for you to set, reuse, or leak. The same sign-in secures the [dashboard](https://dbdock.xyz), the [CLI login](/cloud-sync/authentication), and the [MCP server](/cloud/mcp). ## Credentials at rest Connection and storage credentials you enter in the dashboard are **encrypted at rest**. DBDock uses them to reach your database or bucket when a job runs, and masks them in logs. They're never exposed back to the browser or to MCP clients. ## Account isolation Every request is authenticated and scoped to your own account. You can only see and act on your own connections, backups, storage, schedules, and alerts. In a [team workspace](/cloud/teams), members act on the owner's resources by design — access is shared deliberately within the workspace, not across accounts. ## Encrypted backups Backups are encrypted with AES-256-GCM (see [Encryption](/security/encryption)). Managed storage is encrypted, and backups written to your own bucket are encrypted by DBDock before they leave. ## MCP access The [MCP server](/cloud/mcp) authenticates through the same OAuth flow and confines an assistant to your account. It lets an assistant *ask DBDock to act* — it never hands your database credentials to the client. ## What the CLI sends When you link a project with [Cloud Sync](/cloud-sync/overview), only non-secret metadata is uploaded. Database passwords, storage keys, encryption secrets, and webhook URLs stay on your machine. The full contract is in [Data handling](/cloud-sync/data-handling). ## Your responsibilities Security is shared. DBDock protects the platform; you protect the keys to your data. It's what makes a downloaded backup restorable. Give DBDock only the database and bucket permissions it needs. Remove members when they no longer need access. Use private vulnerability reporting, not public issues. # Encryption Source: https://docs.dbdock.xyz/security/encryption DBDock encrypts backups with AES-256-GCM and PBKDF2 key derivation. How to generate a key, where to store it, credential masking, and PostgreSQL .pgpass support. DBDock encrypts backup files so that a stolen bucket or disk doesn't mean stolen data. Encryption happens after compression, inside the backup [pipeline](/core/concepts). ## Algorithm * **AES-256-GCM** — authenticated encryption * Key derived from your encryption secret via **PBKDF2** (100,000 iterations by default) * A unique initialization vector (IV) per backup * The authentication tag is stored alongside the ciphertext Because GCM authenticates the ciphertext, a tampered backup fails to decrypt rather than silently returning corrupt data. ## Generate an encryption key ```bash theme={null} node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` The key must be exactly **64 hexadecimal characters** (`0`–`9`, `a`–`f`). ## Where to store the key A password manager, secret vault, or cloud KMS. Somewhere separate from the backups. In the backup destination, or in your repository. An attacker with your bucket must not also get the key. **Losing the key means losing the backup.** There is no recovery path for an encrypted backup without its key. Store the key safely — and redundantly — before you rely on encryption in production. ## Rotating the key The short version: decrypt old backups with the old key, re-encrypt with the new one. See the full [Key rotation guide](/guides/key-rotation) for the procedure. ## Encryption in DBDock Cloud DBDock Cloud uses the same AES-256-GCM scheme. On paid plans, encryption is enabled by default for new backups. If you download an encrypted backup to restore it elsewhere, you'll need the encryption secret — treat it with the same care as above. See [Key management](/security/key-management). ## Credential masking DBDock masks credentials in log output by default: ```text theme={null} Connecting to postgresql://postgres:****@host:5432/db ``` This helps prevent accidental leaks when sharing logs. ## PostgreSQL `.pgpass` For host-level credential isolation with PostgreSQL, use the native `.pgpass` file: ```bash theme={null} touch ~/.pgpass chmod 600 ~/.pgpass echo "host:port:database:user:password" >> ~/.pgpass ``` DBDock uses `.pgpass` automatically when present. Environment variables take priority if both are set. `.pgpass` is handy when multiple tools share credentials, or you want OS file permissions gating access. # Key Management Source: https://docs.dbdock.xyz/security/key-management Where DBDock secrets should live — environment variables, secret vaults, and CI secret stores — plus strict mode, least-privilege storage credentials, and key rotation. DBDock's security model rests on one habit: **secrets live in the environment, not in files**. This page covers where to keep them and how to handle them in production and CI. ## The config / secret split `dbdock.config.json` holds non-sensitive settings and is safe to commit. Secrets go in environment variables. See the full table in the [Security overview](/security/overview#secrets-never-live-in-the-config-file). ## Strict mode Have DBDock refuse to run if any secret appears in the config file: ```bash theme={null} DBDOCK_STRICT_MODE=true ``` Use it in CI and production as a safety net against accidental secret leaks in `dbdock.config.json`. ## Where secrets should live A gitignored `.env` file, or your OS keychain. Never commit `.env`. A secret manager or cloud KMS — AWS Secrets Manager, Vault, GCP Secret Manager, etc. Your CI provider's encrypted secret store (GitHub Actions secrets, GitLab CI variables). Inject at runtime. For the CLI in CI, use `DBDOCK_TOKEN` from a secret store. See [Authentication](/cloud-sync/authentication). ## Least-privilege storage credentials Give DBDock only the permissions it needs. For AWS S3 or R2, a scoped policy is enough to put, get, list, and delete backups: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket", "s3:DeleteObject"], "Resource": [ "arn:aws:s3:::my-dbdock-backups", "arn:aws:s3:::my-dbdock-backups/*" ] } ] } ``` On the bucket, also enable server-side encryption, block public access, and turn on versioning for ransomware protection. ## The encryption secret Your backup encryption secret deserves special care — it's the one value that, if lost, makes encrypted backups unrecoverable. Store the encryption secret **separately from the backups themselves**, and keep a redundant copy in a vault or password manager. See [Encryption](/security/encryption). ## Rotating keys Rotate on a schedule and after any suspected exposure. The [Key rotation guide](/guides/key-rotation) walks through rotating your encryption secret without losing access to old backups. ## Related The crypto behind backups. What sync uploads. # Security Overview Source: https://docs.dbdock.xyz/security/overview How DBDock protects your databases, credentials, and backups — encryption by default, secrets kept out of config, tenant isolation in the cloud, and metadata-only sync. DBDock handles sensitive things: database credentials, storage keys, and the contents of your backups. Security isn't a feature bolted on — it shapes how both the CLI and the cloud are built. This page is the map; each area links to the details. ## Principles Backups are encrypted with AES-256-GCM. On DBDock Cloud paid plans, encryption is on by default. Passwords and keys live in environment variables, never in `dbdock.config.json`. Config is safe to commit. Cloud Sync uploads configuration metadata, never credentials or backup contents. Your account's data is scoped to you. Requests are authenticated and access is confined to your own resources. ## The three areas How backups are encrypted, credential masking, and `.pgpass`. Sign-in, data at rest, isolation, and the MCP server. Where secrets should live, in CI and in production. ## Secrets never live in the config file DBDock enforces a strict split between non-sensitive configuration and secrets: | Lives in `dbdock.config.json` (safe to commit) | Lives in the environment (never commit) | | ---------------------------------------------- | --------------------------------------- | | Host, port, database name, username | Database password | | Bucket names, regions, endpoints | Storage access/secret keys | | SMTP host, port, sender address | SMTP password | | "Slack enabled" flag | Slack webhook URL | | "Encryption enabled" flag | Encryption secret | This same split is what makes [Cloud Sync](/cloud-sync/data-handling) safe: the parts that are safe to commit are the parts that sync, and nothing else. ## Credential masking DBDock masks credentials in log output by default, so pasting logs into an issue or sharing your screen doesn't leak a password: ```text theme={null} Connecting to postgresql://postgres:****@host:5432/db ``` ## Reporting a vulnerability Please do **not** file public GitHub issues for security vulnerabilities. * Use GitHub's [private vulnerability reporting](https://github.com/dbdock/dbdock/security/advisories/new), or * See [SECURITY.md](https://github.com/dbdock/dbdock/blob/main/SECURITY.md) for how to report and expected response times. # Cloudinary Source: https://docs.dbdock.xyz/storage/cloudinary Media-platform storage with a generous free tier. Cloudinary is primarily a media platform, but its media library doubles as a convenient backup target. The free tier (25 credits/month, \~25 GB storage) covers most small-to-medium databases. ## Configuration ### `dbdock.config.json` ```json theme={null} { "storage": { "provider": "cloudinary", "cloudinary": { "cloudName": "your-cloud-name" } } } ``` ### `.env` ```bash theme={null} DBDOCK_CLOUDINARY_API_KEY=your-api-key DBDOCK_CLOUDINARY_API_SECRET=your-api-secret ``` Find your credentials in the [Cloudinary Console](https://console.cloudinary.com/) dashboard. ## Setup Sign up at [cloudinary.com](https://cloudinary.com/). Free tier is fine for getting started. Console → Dashboard → Account Details. * **Cloud name** → `cloudName` in config * **API Key** → `DBDOCK_CLOUDINARY_API_KEY` * **API Secret** → `DBDOCK_CLOUDINARY_API_SECRET` ```bash theme={null} npx dbdock test ``` Backups land in the `dbdock_backups/` folder of your Media Library. ## When to pick Cloudinary Sign up in 2 minutes, start backing up. 25 GB for small teams, indefinitely. If you host images/videos on Cloudinary already, reuse the account. The Media Library lets you browse/download backups through a friendly UI. ## When to NOT pick Cloudinary * **Large databases.** Past \~25 GB you'll hit the free tier wall and paid plans aren't cost-competitive with S3/R2 for pure storage. * **High backup frequency.** Every backup counts as a transformation. Daily backups are fine; per-hour backups will burn through credits. * **Compliance (HIPAA, SOC 2).** S3 has a more mature compliance story. ## File organization Backups are stored as raw files under `dbdock_backups/`. Filenames follow DBDock's standard format: ``` dbdock_backups/backup-2026-04-16-08-00-00-abc123.sql ``` You can browse them in the Cloudinary Media Library, though they're not useful to preview — they're encrypted/compressed binary blobs. ## Common errors * Double-check `DBDOCK_CLOUDINARY_API_KEY` and `DBDOCK_CLOUDINARY_API_SECRET` * Make sure `cloudName` matches the "Cloud name" field exactly (case sensitive) * Check Cloudinary account usage — you may have hit the free tier quota * Verify the API key has "Media library" access * The file must be in `dbdock_backups/` folder (DBDock writes here by default) * Filename must match the standard pattern ## Cost Free tier covers: * 25 monthly credits (1 credit ≈ 1 GB of storage or \~1000 transformations) * Up to 25 GB total storage Past that, the Plus plan (\$99/month) gives 225 GB. If you're at this level, S3 or R2 will be significantly cheaper for pure backup storage. ## See also Cheaper for large databases. Zero egress fees. # Deletion safety Source: https://docs.dbdock.xyz/storage/deletion-safety How DBDock protects backups in object storage from accidental or runaway deletion. Backups are only useful if they are still there when you need them. DBDock applies several layers of protection so that retention, cleanup, and manual deletes can never remove the wrong object — and so that a delete can be undone. ## What is protected Every delete that DBDock performs against object storage (S3, Cloudflare R2, Cloudinary, or local) passes through a guard before anything is removed. This covers automatic retention, WAL cleanup, and the `dbdock delete` / `dbdock cleanup` commands, on both DBDock-managed storage and your own buckets. ## Layer 1 — Delete guard Before any object is deleted, the key is validated and checked against an allow-list of DBDock-owned prefixes: * **Structural checks** — empty keys, surrounding whitespace, leading slashes, folder-style keys (`.../`), path traversal (`..`), and wildcards are refused. * **Prefix allow-list** — keys must live under a DBDock prefix (`backups/`, `wal/`, `dbdock_backups/`, or `backup-`). Anything outside the namespace DBDock created is never a deletion target. * **Circuit breaker** — a single run cannot delete more than `maxDeletesPerWindow` objects within a rolling window (default 1000 per minute), so a bug in a retention policy can't cascade into wiping a bucket. If a check fails, the delete is refused and the object is left untouched. ## Layer 2 — Recycle bin Deletes are **soft by default**. Instead of being removed immediately, an object is copied to a `.trash//` prefix (a fast server-side copy on S3/R2) and only then removed from its original location. A small `.trashmeta.json` sidecar records the original key, the time, and the reason. Trashed objects are hard-purged automatically once they are older than `trashRetentionDays` (default 14 days), and can be restored before then. ```ts theme={null} const storage = app.get(StorageService); const restoredKey = await storage.restoreFromTrash( '.trash/2026-06-19T22-31-00-000Z/backups/db/2026-06-19/abc.sql.gz', ); ``` ## Layer 3 — Bucket versioning (recommended for R2/S3) The recycle bin lives inside the same bucket. For protection against bucket-level mistakes (a bad lifecycle rule, a compromised key, an accidental bucket action), enable **object versioning** on the bucket itself so deletes become recoverable delete-markers. In the Cloudflare dashboard open **R2 → your bucket → Settings → Object versioning** and turn it on. On AWS S3, enable **Bucket Versioning** under the bucket's **Properties**. Add a lifecycle rule to expire **non-current** versions after a retention window (for example 30 days) so old versions don't accumulate cost. Give DBDock an API token scoped to a single bucket with only the object read/write/delete permissions it needs — not account-wide access. ## Configuration All of layer 1 and layer 2 are on by default. Tune them under `storage.deletionSafety`: ```json theme={null} { "storage": { "provider": "r2", "deletionSafety": { "enabled": true, "recycleBin": true, "trashRetentionDays": 14, "maxDeletesPerWindow": 1000 } } } ``` | Field | Default | Description | | --------------------- | ------------ | --------------------------------------------------------- | | `enabled` | `true` | Master switch for the guard and allow-list. | | `recycleBin` | `true` | Soft-delete to `.trash/` instead of deleting immediately. | | `trashRetentionDays` | `14` | Days a trashed object is kept before it is purged. | | `maxDeletesPerWindow` | `1000` | Circuit-breaker limit per rolling minute. | | `allowedPrefixes` | DBDock roots | Override the protected prefix allow-list. | # Local storage Source: https://docs.dbdock.xyz/storage/local Store backups on the local filesystem. Local storage writes backups to a directory on disk. It's the fastest option and requires no cloud account. ## Configuration ```json theme={null} { "storage": { "provider": "local", "local": { "path": "./backups" } } } ``` Or via environment: ```bash theme={null} STORAGE_PROVIDER=local STORAGE_LOCAL_PATH=./backups ``` ## File layout ``` ./backups/ dbdock_backups/ backup-2026-04-16-08-00-00-abc123.sql backup-2026-04-16-08-00-00-abc123.meta.json ... ``` ## Recommended practices ### Directory permissions Owner-only access: ```bash theme={null} chmod 700 ./backups ``` ### Use an absolute path in production Relative paths resolve from wherever DBDock is invoked, which gets confusing fast: ```json theme={null} { "storage": { "provider": "local", "local": { "path": "/var/backups/myapp" } } } ``` ### Enable filesystem encryption Local backups are not encrypted by DBDock if the `encryption` config is off. Rely on disk encryption (LUKS, FileVault, BitLocker) or enable DBDock's encryption layer for defense in depth. ### Watch disk space Local backups accumulate. Set a retention policy: ```json theme={null} { "backup": { "retention": { "enabled": true, "maxBackups": 14, "maxAgeDays": 14, "minBackups": 3, "runAfterBackup": true } } } ``` ## When local is the right choice * Single-server setup with dedicated backup disk * Development and testing * Staging databases you don't mind losing in a host failure * A first hop before syncing to cloud (e.g., rsync to another host) ## When local is the wrong choice * **Production data you can't afford to lose.** If the server dies, the backups die with it. * **Multi-server deployments.** Backups get fragmented across hosts. * **Compliance environments.** Audit trails are usually easier with object storage. Pair local with a cloud provider for disaster recovery — take backups locally for speed, then sync to S3/R2 on a schedule. ## See also Offsite backup destination. Cheaper cloud alternative. # DBDock Storage Source: https://docs.dbdock.xyz/storage/managed Managed backup storage included with your plan — no bucket, no keys. DBDock Storage is managed object storage that ships with your DBDock plan. Pick it in `dbdock init` and backups upload straight to your quota — you never create a bucket or paste an access key. DBDock Storage needs a signed-in account. Run `dbdock login` first. It's available on Pro and Business plans, with a small free-tier allowance for trying it out. ## How it works The CLI never holds the storage bucket's credentials. Every upload and download goes through a short-lived presigned URL that the DBDock backend issues for your account only: 1. `dbdock backup` writes the finished backup to a temp file. 2. The CLI asks the backend for a presigned upload URL. The backend checks your quota and scopes the object to your account's private prefix. 3. The CLI uploads directly to storage using that URL, then removes the temp file. 4. `dbdock restore` reverses it with a presigned download URL. Because keys are scoped server-side, one account can never read or write another account's backups. ## Setup ```bash theme={null} npx dbdock login # one-time browser sign-in npx dbdock init # choose "DBDock Storage (recommended)" ``` `init` activates managed storage for your account and shows your current quota. The written `dbdock.config.json` is just: ```json theme={null} { "storage": { "provider": "managed" } } ``` No secrets land in the config file or `.env`. ## Everyday use ```bash theme={null} npx dbdock backup # uploads to your managed quota npx dbdock list # lists your managed backups npx dbdock restore # restores from a managed backup npx dbdock storage # shows usage vs. quota npx dbdock delete # removes a managed backup ``` ## Quotas Usage is measured from what's actually stored, so CLI and dashboard backups both count. Quota by plan: | Plan | Included storage | | -------- | ---------------- | | Free | 1 GB | | Pro | 50 GB | | Business | 500 GB | When a backup would push you over quota, the upload is refused before anything is stored. Free up space with `dbdock delete` or `dbdock cleanup`, or upgrade your plan. ## When to use it * You want backups offsite without running your own bucket. * You don't want storage keys living in config files or CI secrets. * You already pay for DBDock and would rather not add a separate storage bill. ## When to use your own bucket instead * You need backups in a specific region, account, or compliance boundary you control. * You want to keep more data than your plan's quota allows. * You have existing lifecycle or replication rules on your bucket. In those cases pick [S3](/storage/s3), [R2](/storage/r2), or [local](/storage/local) in `init`. ## See also Check your usage and quota. See your plan and limits. # Storage overview Source: https://docs.dbdock.xyz/storage/overview Choose where DBDock puts your backups. DBDock supports five storage backends, all exposed through the same config shape and all swappable without re-configuring backups. Managed storage included with your plan — no bucket, no keys. Recommended. Filesystem storage — fastest, no network, no cost. Industry standard, mature ecosystem. Any S3-compatible service works. Zero egress fees — if you restore frequently, this is the cheapest cloud option. Generous free tier, fastest to get started, no AWS/Cloudflare account needed. ## Picking a provider | You want... | Use | | -------------------------------------------- | -------------------------------------- | | Backups offsite with zero setup | DBDock Storage | | Fastest possible backup/restore | Local (if single server) | | Standard cloud backup with wide tool support | S3 | | Cheap cloud storage with no egress fees | R2 | | Free tier, no cloud account | Cloudinary | | Multi-region backup destination | S3 or R2 with cross-region replication | | Compliance (HIPAA, SOC 2) | S3 with KMS + bucket policies | ## How DBDock uses storage Regardless of provider: 1. Backup is **streamed** (never buffered to disk) to the provider 2. Files live under a `dbdock_backups/` prefix with standardized naming 3. Metadata is stored alongside each backup for `list` and `restore` 4. Deletion is always soft — you'll confirm before anything is removed ## File layout ``` / dbdock_backups/ backup-2026-04-16-08-00-00-abc123.sql backup-2026-04-16-08-00-00-abc123.meta.json backup-2026-04-15-08-00-00-def456.sql backup-2026-04-15-08-00-00-def456.meta.json ... ``` The metadata file tracks size, compression, encryption, duration, and origin. ## Switching providers You can switch anytime. Existing backups stay in the old provider; new backups go to the new one. To consolidate, manually move old files or do a `dbdock list` on each provider and track both. ## See also How storage is configured. Storage security best practices. # Cloudflare R2 Source: https://docs.dbdock.xyz/storage/r2 S3-compatible storage with zero egress fees. Cloudflare R2 is S3-compatible object storage with **no egress fees** — ideal when you restore backups frequently or pull them to different regions. ## Configuration ### `dbdock.config.json` ```json theme={null} { "storage": { "provider": "r2", "s3": { "bucket": "my-dbdock-backups", "region": "auto", "endpoint": "https://.r2.cloudflarestorage.com" } } } ``` Find your `ACCOUNT_ID` in the Cloudflare dashboard → R2 sidebar. The region is always `auto` for R2. ### `.env` ```bash theme={null} DBDOCK_STORAGE_ACCESS_KEY=your-r2-access-key-id DBDOCK_STORAGE_SECRET_KEY=your-r2-secret-access-key ``` ## Bucket setup Cloudflare dashboard → R2 → Create bucket. Pick a name and location hint. Cloudflare dashboard → R2 → Manage API Tokens → Create API Token. Permissions needed: **Object Read & Write**. Scope to the specific bucket. Copy the **Access Key ID** and **Secret Access Key** — they're shown once. The endpoint format requires your account ID: `https://.r2.cloudflarestorage.com` Find the account ID on the right sidebar of any Cloudflare dashboard page. ```bash theme={null} npx dbdock test ``` ## Why R2 over S3 Downloads cost nothing. S3 charges \$0.09/GB. Same client, same tools — no lock-in. Cloudflare's global network caches R2. Storage \$0.015/GB/month + operations. No surprise bills. ## When to pick R2 vs S3 | Pick R2 if... | Pick S3 if... | | ------------------------------------- | ------------------------------------------------------- | | You restore backups often | You never pull backups out of AWS | | You serve backups to multiple regions | Your compute is already in AWS | | Cost predictability matters | You need deep AWS integration (KMS, Glacier, IAM roles) | | You're already using Cloudflare | You're already using AWS | ## Public URLs R2 supports public buckets via custom domains (`backups.example.com`). DBDock does **not** use this — backups are private and accessed with signed credentials. Keep your R2 bucket private. ## Common errors * Bucket name is misspelled * Account ID in endpoint is wrong * API token doesn't have Object Read & Write * Token is scoped to a different bucket * Endpoint must be `https://.r2.cloudflarestorage.com` (not `https://pub-.r2.dev`) * No trailing slash ## Cost comparison Example: 100 MB daily backup, 30-day retention, 3 restores/month (300 MB egress): | Provider | Storage | Requests | Egress | Total | | --------------- | ------- | -------- | ---------- | --------------- | | **R2** | \$0.045 | \~\$0.01 | **\$0.00** | **\~\$0.06/mo** | | **S3 Standard** | \$0.069 | \~\$0.01 | \$0.027 | \~\$0.11/mo | Small numbers individually, but over many databases and many months the egress difference matters. ## Protecting backups from deletion DBDock soft-deletes to a recycle bin and refuses deletes outside its own prefixes by default. For bucket-level protection, also enable **R2 object versioning** so deletes become recoverable delete-markers. See [Deletion safety](/storage/deletion-safety). ## See also The incumbent, more features. Another option with a generous free tier. # AWS S3 Source: https://docs.dbdock.xyz/storage/s3 Store backups in Amazon S3 or any S3-compatible service. DBDock uses the AWS SDK under the hood, so anything S3-compatible works: AWS S3, MinIO, Wasabi, DigitalOcean Spaces, Backblaze B2, etc. ## Configuration ### `dbdock.config.json` ```json theme={null} { "storage": { "provider": "s3", "s3": { "bucket": "my-dbdock-backups", "region": "us-east-1" } } } ``` For non-AWS S3-compatible services, add `endpoint`: ```json theme={null} { "storage": { "provider": "s3", "s3": { "bucket": "my-dbdock-backups", "region": "us-east-1", "endpoint": "https://s3.wasabisys.com" } } } ``` ### `.env` ```bash theme={null} DBDOCK_STORAGE_ACCESS_KEY=AKIA... DBDOCK_STORAGE_SECRET_KEY=... ``` ## Required IAM permissions Create a dedicated IAM user for DBDock with **least-privilege** access: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:ListBucket", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::my-dbdock-backups", "arn:aws:s3:::my-dbdock-backups/*" ] } ] } ``` Replace `my-dbdock-backups` with your bucket name. The IAM user does not need any other permissions. ## Bucket setup AWS Console → S3 → Create bucket. Pick a region close to your database. Under "Block Public Access", enable **all four** settings. Backups should never be public. Under "Bucket Versioning", enable it. This protects against ransomware — deleted backups can be recovered. Under "Default encryption", enable SSE-S3 (AES-256) or SSE-KMS. DBDock's own encryption layer is separate — both work together. Move backups older than N days to Glacier or delete them via S3 lifecycle rules. Cheaper than keeping everything in Standard. ## Testing the connection ```bash theme={null} npx dbdock test ``` Look for the `Storage: AWS S3` section in the output. DBDock uploads a tiny test object and deletes it to verify full read/write/delete permissions. ## Cross-region replication If you need multi-region disaster recovery, configure S3 Cross-Region Replication (CRR) on the bucket. DBDock is agnostic to this — it writes to the primary and S3 handles the replication. ## S3-compatible services Tested combinations: | Service | Endpoint | Notes | | ----------------------- | ----------------------------------------- | ------------------------------- | | **AWS S3** | (omit) | Default | | **MinIO** | `https://minio.example.com` | Self-hosted | | **Wasabi** | `https://s3.wasabisys.com` | Cheaper S3-compatible | | **DigitalOcean Spaces** | `https://.digitaloceanspaces.com` | | | **Backblaze B2** | `https://s3..backblazeb2.com` | Use B2's S3-compatible endpoint | ## Common errors * Check IAM policy is attached to the user * Bucket name is correct and in the right region * If using S3 block public access, IAM policy must explicitly allow the actions above * Bucket name is misspelled * Bucket exists in a different region — set `region` correctly * Access/secret key pair is wrong or expired * Clock drift on the machine running DBDock (S3 requires ±15 min of accurate time) ## Cost considerations For a typical setup (daily backup, 30-day retention, \~100 MB compressed backup): * **Storage:** 3 GB × $0.023/GB ≈ $0.07/month * **Requests:** \~60 PUT + 100 GET/LIST = negligible * **Egress on restore:** \$0.09/GB outside AWS R2 and Cloudinary have no egress fees — worth considering if you restore often. ## See also Zero-egress S3-compatible alternative. Storage security best practices.