n8n Backup Restore Workflow Database Migration Guide
I back up my n8n workflows every night because losing a workflow is like losing a piece of your operational brain. Here’s the exact backup and migration strategy I’ve refined over two years of running n8n in production.
Backups serve two purposes. First, disaster recovery — if the server dies, you restore from the last backup. Second, migration — moving workflows between environments without rebuilding them from scratch. Both require the same tools, just different timing.
The n8n data model separates workflows, credentials, and execution history. Each lives in a different place. A complete backup captures all three.
What Needs Backing Up
Three components make up a full n8n backup:
1. Workflows — the visual automation definitions, node configurations, and connections
2. Credentials — API keys, OAuth tokens, and authentication secrets
3. Database — workflow metadata, execution history, and system configuration
Workflows and credentials are exportable via the CLI or API. The database depends on your storage backend — SQLite for local installs, PostgreSQL for production deployments.
I back up workflows and credentials manually through the CLI. The database backs up automatically through the underlying storage engine. This separation gives me granular control over what gets restored and when.
Exporting Workflows with the CLI
The n8n CLI provides straightforward export commands:
`bash
Export a single workflow
n8n export –workflowId=123 –output=./backups/workflow-123.json
Export all workflows to a single file
n8n export –all –output=./backups/all-workflows.json
Export workflows to individual files
n8n export –all –output-dir=./backups/workflows/
`
The individual file export creates one JSON file per workflow, named by workflow ID. This is cleaner for version control — each workflow gets its own file in a Git repository.
Include timestamps in your backup filenames for easy identification:
`bash
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
n8n export –all –output=”./backups/all-workflows-${TIMESTAMP}.json”
`
The exported JSON includes the workflow name, active status, nodes, connections, and settings. It does not include credential values — those are stored encrypted in the n8n database and exported separately.
Exporting Credentials
Credentials require a separate export command:
`bash
Export all credentials
n8n export –credentials –output=./backups/all-credentials.json
Export specific credential type
n8n export –credentials –filter=apiKey –output=./backups/api-keys.json
`
The credential export includes the credential name, type, and encrypted data. The encryption key is stored in the n8n environment variable N8N_ENCRYPTION_KEY. Without this key, restored credentials are useless.
Store the encryption key separately from the credential backup:
`bash
Save encryption key to a secure location
echo “$N8N_ENCRYPTION_KEY” > ./backups/encryption-key.txt
chmod 600 ./backups/encryption-key.txt
`
File permission 600 means only the owner can read the file. The encryption key is effectively a master password for all your stored credentials.
Database Backups
The database backup strategy depends on your storage type.
For SQLite (default for local development):
`bash
Stop n8n to ensure consistent backup
systemctl stop n8n
Copy the database file
cp /var/lib/n8n/database.sqlite ./backups/database-$(date +%Y%m%d).sqlite
Restart n8n
systemctl start n8n
`
Stopping n8n during the copy ensures you don’t capture a partially-written database. The copy takes milliseconds for typical workflow databases. For large databases with extensive execution history, consider using SQLite’s built-in backup functionality instead.
For PostgreSQL (production deployments):
`bash
Full database dump
pg_dump -U n8n_user -d n8n_database -F c -f ./backups/postgres-$(date +%Y%m%d).dump
Schema only (no data)
pg_dump -U n8n_user -d n8n_database -s -f ./backups/schema-$(date +%Y%m%d).sql
Data only
pg_dump -U n8n_user -d n8n_database –data-only -f ./backups/data-$(date +%Y%m%d).sql
`
PostgreSQL offers incremental backups through WAL archiving. Enable it in your postgresql.conf:
`conf
wal_level = replica
archive_mode = on
archive_command = ‘cp %p /var/lib/pg_wal_archive/%f’
`
WAL archiving allows point-in-time recovery. You can restore to any moment between backups, not just the last backup point.
Automated Backup Script
Here’s a complete backup script I run nightly via cron:
`bash
#!/bin/bash
set -euo pipefail
BACKUP_DIR=”/var/backups/n8n”
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
RETENTION_DAYS=30
mkdir -p “$BACKUP_DIR/workflows”
mkdir -p “$BACKUP_DIR/credentials”
mkdir -p “$BACKUP_DIR/database”
echo “[$TIMESTAMP] Starting n8n backup…”
Export workflows
n8n export –all –output=”$BACKUP_DIR/workflows/all-$TIMESTAMP.json”
Export credentials
n8n export –credentials –output=”$BACKUP_DIR/credentials/all-$TIMESTAMP.json”
Backup database (SQLite example)
cp /var/lib/n8n/database.sqlite “$BACKUP_DIR/database/db-$TIMESTAMP.sqlite”
Compress old backups
find “$BACKUP_DIR” -name “.json” -o -name “.sqlite” | xargs gzip 2>/dev/null || true
Clean up old backups
find “$BACKUP_DIR” -mtime +$RETENTION_DAYS -delete
echo “[$TIMESTAMP] Backup complete.”
`
Make it executable and schedule with cron:
`bash
chmod +x /usr/local/bin/n8n-backup.sh
echo “0 3 * /usr/local/bin/n8n-backup.sh” | crontab –
`
The script runs at 3 AM daily. It exports workflows, credentials, and the database. Old backups compress automatically. Anything older than 30 days gets deleted.
For PostgreSQL, replace the SQLite copy command with the pg_dump command from the previous section.
Restoring from Backup
Restore follows the same sequence as export, but in reverse order:
`bash
1. Stop n8n
systemctl stop n8n
2. Restore database
cp ./backups/database/db-20260701.sqlite /var/lib/n8n/database.sqlite
3. Start n8n
systemctl start n8n
4. Wait for n8n to be ready
sleep 10
5. Import workflows
n8n import –all –input=./backups/workflows/all-20260701.json
6. Import credentials
n8n import –credentials –input=./backups/credentials/all-20260701.json
`
The database must be restored before workflows. Workflows reference database entries for credential IDs and execution history. Restoring workflows first creates orphaned references.
If you’re migrating to a new server, the process is similar but includes environment setup:
`bash
1. Install n8n on new server
npm install -g n8n
2. Configure environment (database, encryption key, etc.)
export N8N_ENCRYPTION_KEY=”your-encryption-key-here”
export DB_TYPE=postgresdb
export DB_POSTGRESDB_HOST=new-server-db.example.com
3. Start n8n to initialize database
n8n start &
sleep 15
4. Import workflows and credentials
n8n import –all –input=./backups/workflows/all-20260701.json
n8n import –credentials –input=./backups/credentials/all-20260701.json
5. Verify import
n8n export –all –output=./verify-export.json
diff ./backups/workflows/all-20260701.json ./verify-export.json
`
The diff command shows any differences between the backup and the restored export. If they match, the migration succeeded.
Migration Between Environments
Moving workflows from development to production follows the same export/import pattern. The key differences:
1. Different database connections — production uses PostgreSQL, development uses SQLite
2. Different credentials — production API keys differ from development keys
3. Different base URLs — workflow webhook URLs must be updated
Update webhook URLs after migration:
`bash
Find all workflows with webhook nodes
n8n export –all –output=./all-wfs.json
Edit webhook URLs in the JSON
sed -i ‘s|https://dev.n8n.example.com|https://prod.n8n.example.com|g’ ./all-wfs.json
Import edited workflows
n8n import –all –input=./all-wfs.json
`
The sed command replaces all development URLs with production URLs in one pass. Test this on a staging environment before applying to production.
For credential updates, re-authenticate each credential type after migration:
`bash
List all credentials
n8n export –credentials –output=./creds-list.json
Re-authenticate API credentials
(manually through the web UI or API)
`
Re-authenticating ensures the new environment uses current credentials. Old OAuth tokens expire. API keys rotate. Fresh authentication prevents silent failures.
Connecting to Your Existing Setup
If you’re running n8n in Docker, the n8n Docker Deployment guide covers volume mounting for persistent storage. Mount the database directory to a persistent volume to simplify backups.
The n8n Docker Compose production stack includes a backup service configuration. It runs automated backups on a schedule, eliminating the need for a custom cron script.
Understanding n8n’s database architecture helps you choose the right backup strategy. PostgreSQL supports point-in-time recovery. SQLite requires file-level copies.
Action Card: Quick Restore
Emergency restore in three commands:
`bash
1. Stop n8n
systemctl stop n8n
2. Restore database from latest backup
cp /var/backups/n8n/database/db-$(ls /var/backups/n8n/database/ | tail -1) /var/lib/n8n/database.sqlite
3. Start n8n and re-import
systemctl start n8n
n8n import –all –input=/var/backups/n8n/workflows/all-$(ls /var/backups/n8n/workflows/ | tail -1).json
`
This restores the most recent backup. You lose executions that happened between the backup and the failure. That’s acceptable for most recovery scenarios.
