A workflow export is not a full instance backup. Protect the database, encryption key, deployment configuration, and binary storage, then prove that they work together on an isolated restore.
A recoverable self-hosted n8n backup has four core parts: the database, the original encryption key, the deployment configuration and secrets, and any binary-data storage your executions still need.
Back up the persistent .n8n volume even when PostgreSQL stores the main database. n8n documents that this directory can still contain the encryption key, logs, and source-control assets.
What must be in the backup
| Asset | Why it matters | Typical location |
|---|---|---|
| Database | Workflows, encrypted credentials, users, projects, settings, and retained execution data |
~/.n8n/database.sqlite or PostgreSQL |
| Encryption key | Decrypts credentials stored in the database |
~/.n8n settings or N8N_ENCRYPTION_KEY
|
| Deployment config | Restores database connection, public URL, proxy, timezone, pruning, and execution behavior | Compose file, environment settings, secret references, proxy config |
| Binary data | Restores retained files handled by executions | Persistent filesystem, database, or configured external store |
| Custom and community nodes | Allows restored workflows to load the same node types and versions | Package list, custom-node directory, container image, or build manifest |
Do not put the raw encryption key, database password, OAuth secrets, or an unredacted environment file in a public repository. Keep a sanitized deployment definition in version control and protect the actual secrets in a restricted password manager, secret store, or encrypted backup.
Choose the database path first
Self-hosted n8n uses SQLite by default. The database file is ~/.n8n/database.sqlite. PostgreSQL is the other supported database option. The backup and restore commands must match the database your instance actually uses.
SQLite: capture a consistent persistent volume
The simplest small-instance method is a short maintenance window: stop the n8n application, archive its persistent volume, then start it again. Stopping writes avoids treating an arbitrary live file copy as a consistent database backup.
docker compose stop n8n
docker run --rm \
-v n8n_data:/data:ro \
-v "$PWD/backups:/backup" \
alpine tar czf /backup/n8n-data-2026-07-18.tgz -C /data .
docker compose start n8n
Replace the service and volume names with the names in your deployment. If downtime is not acceptable, use a storage snapshot or SQLite-aware backup process that guarantees a consistent result. Do not assume that copying database.sqlite while executions are writing to it is safe.
PostgreSQL: use a database dump
PostgreSQL's official documentation recommends pg_dump for logical backups. A custom-format dump works with pg_restore and is practical for restoring into a fresh database:
pg_dump --format=custom --file=n8n-2026-07-18.dump n8n
The dump does not replace the n8n persistent volume or explicit encryption key. It also does not capture the Compose file, environment settings, proxy configuration, or filesystem binary data. Store those as separate parts of the same dated backup set.
Add native n8n exports as a second recovery layer
n8n's Server CLI can export all database entity types. Its documentation positions this tooling for backups and migrations, including moves between SQLite and PostgreSQL. Execution-history data tables are excluded by default because they can be large.
docker exec -u node n8n \
n8n export:entities \
--outputDir=/home/node/.n8n/cli-backup
Workflow and credential exports are also useful for selective recovery or versioned copies:
n8n export:workflow --backup --output=backups/workflows/
n8n export:credentials --backup --output=backups/credentials/
Avoid decrypted credential exports for routine backups. n8n supports a
--decryptedflag for migrations to a different secret key, but the resulting files expose every sensitive value in plain text.
A safe restore runbook
First restore into an isolated instance with no production webhooks, schedules, email sends, payment calls, or CRM writes. The first recovery test should never overwrite the only production copy.
- Record the target. Use the same n8n version first, the same database type, and compatible custom-node versions.
- Create fresh infrastructure. Prepare a new Docker volume or empty PostgreSQL database rather than clearing production.
-
Restore the original encryption key. Put the protected
N8N_ENCRYPTION_KEYor original n8n settings in place before n8n reads the restored credentials. - Restore the database. Extract the stopped SQLite volume archive into the new volume, or restore the PostgreSQL dump into the new database.
- Restore the surrounding state. Reapply deployment settings, binary storage, custom nodes, public URL settings, and reverse-proxy configuration.
- Start without production traffic. Keep DNS, proxy routing, and outbound side effects isolated while checking startup and migration logs.
- Verify the application. Confirm login, projects, workflows, credentials, node availability, required execution history, and retained binary files.
- Run one safe test. Use test credentials or a non-destructive workflow and confirm that a credential can decrypt and authenticate.
- Publish deliberately. Review which workflows should be published before switching traffic.
Restore SQLite into a new volume
docker volume create n8n_restore_data
docker run --rm \
-v n8n_restore_data:/data \
-v "$PWD/backups:/backup:ro" \
alpine tar xzf /backup/n8n-data-2026-07-18.tgz -C /data
Point a separate restore Compose file at n8n_restore_data. Do not bind it to the production hostname or webhook route until the checklist passes.
Restore PostgreSQL into a fresh database
createdb n8n_restore
pg_restore --dbname=n8n_restore n8n-2026-07-18.dump
Real deployments may need explicit host, user, role, ownership, TLS, and schema options. Test the exact command your operator will use and document it without embedding the password.
Restore-test checklist
- The backup job has a timestamp, size, success state, and failure alert.
- The database and encryption key come from the same recoverable setup.
- The restore starts on a separate hostname, volume, and database.
- Credential nodes open without decryption errors and one test authentication succeeds.
- Required custom or community nodes load at the expected versions.
- Published workflows, schedules, and webhook paths are reviewed before traffic moves.
- Required retained binary files can be opened.
- The restore time and missing manual steps are recorded for the next test.
Common backup failures
| Mistake | What breaks during recovery |
|---|---|
| Only exporting workflow JSON | The complete instance state is not restored |
| Database without the original key | Credentials remain encrypted but cannot be used |
| Copying a live SQLite file casually | The backup may not represent one consistent database state |
| Skipping binary storage | Retained documents or images may be missing |
| Restoring straight over production | A bad archive or wrong config can remove the working recovery path |
| Never testing the restore | Missing keys, permissions, packages, and manual steps appear during the incident |
Sources
- n8n Docker persistence and PostgreSQL guidance
- n8n supported databases and SQLite location
- n8n encryption-key behavior
- n8n Server CLI export and import commands
- n8n binary-data storage modes
- PostgreSQL SQL dump documentation
- SQLite online backup documentation
Originally published on FloxoLab.
Top comments (0)