# 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