Self-Hosted n8n Backup and Restore: A Complete Disaster Recovery Plan
A complete backup and restore plan for self-hosted n8n: the database, the encryption key, CLI exports, offsite storage, and a tested quarterly restore drill.

If your self-hosted n8n server died tonight, could you rebuild it tomorrow morning with every workflow, credential, and webhook intact? Most teams running n8n in production cannot honestly answer yes, because their backup is a daily pg_dump and a hope. A working n8n backup protects five distinct things, stores them off the server, and gets restored in a drill at least once a quarter. This guide gives you that system.
The advice below follows n8n's own backup and restore documentation and extends it with the operational details the docs leave out: scripts, retention schedules, offsite costs, and the mistakes that only show up during an actual restore.
What a complete n8n backup actually includes
A complete backup of a self-hosted n8n instance has two mandatory parts, per the official docs:
- The
.n8nuser folder (~/.n8nby default). This holds theconfigfile, which stores the credential encryption key. With the default SQLite database it also holds the database file itself. If binary data or execution data uses filesystem storage mode, that data lives here too. - Your external database, if you run PostgreSQL instead of SQLite. Back it up with PostgreSQL's own tooling. The
.n8nfolder is still required, because credentials stored in the database are encrypted with the key that folder holds.
Two more items round out a real-world backup:
- External storage, if you configured S3 or Azure Blob for binary or execution data.
- Custom node directories, if you load community nodes from paths set in
N8N_CUSTOM_EXTENSIONS. A restored instance without them is missing the nodes its workflows reference, and those workflows will fail to load.
If you run n8n in Docker, the .n8n folder lives in the n8n_data volume, mounted at /home/node/.n8n. Your docker-compose.yml, .env file, and reverse proxy config are also part of the backup: without them you are reconstructing your deployment from memory at the worst possible time.
One consistency rule matters: with the default SQLite database, stop n8n before copying the .n8n folder. Copying the database file while n8n is writing to it can produce a corrupt backup that looks fine until you try to restore it. This is one of the practical reasons production instances should run PostgreSQL: pg_dump makes consistent exports while the database is in use, without blocking readers or writers, as the PostgreSQL documentation confirms.
The encryption key is the single point of failure
Every credential in n8n, every API key, OAuth token, database password, and SMTP login, is encrypted before it is written to the database. The key is either a random one n8n generates on first launch or one you set yourself with the N8N_ENCRYPTION_KEY environment variable, as documented in the deployment environment variables reference.
This creates a failure mode that surprises people: if you restore a perfect database backup onto a new server but the encryption key is different, n8n starts normally. The UI loads. Your workflows appear. And every single credential fails to decrypt the moment a workflow tries to authenticate. There is no reset mechanism and no recovery path. The only fix is the original key.
Treat the key accordingly:
- Store it in a password manager as a secure note, named clearly: "n8n production encryption key, server X".
- Keep a second copy in a secrets vault or as a GPG-encrypted file in a different location from the server.
- Never store it only on the n8n server itself. A disk failure that takes the database also takes the key, and now your backups are encrypted garbage.
Verify the stored copy today: run grep N8N_ENCRYPTION_KEY on your .env file and compare it character by character with what you saved. Discovering a mismatch during a disaster recovery is a scenario you want to eliminate entirely.
If you ever rotate the key, note that the rotation feature flag N8N_ENV_FEAT_ENCRYPTION_KEY_ROTATION is a one-way change, and n8n's own docs tell you to take a full database backup first.
Database backups with pg_dump
For a PostgreSQL-backed instance, pg_dump is the core of the backup. Use the custom archive format: it is compressed by default, supports selective restore of individual tables through pg_restore, and restores faster than plain SQL dumps.
A manual dump looks like this:
mkdir -p ~/n8n-backups/db
docker exec n8n-postgres \
pg_dump -U n8n -d n8n --format=custom \
> ~/n8n-backups/db/n8n-db-$(date +%Y%m%d-%H%M%S).dump
Automate it with cron, but with one critical guard: verify the dump file is not empty. A docker exec against a stopped container fails silently in some shells and leaves you a zero-byte file that looks like a backup. A production backup script should:
- Run pg_dump with
--format=custom - Test the output with
[ -s file ]and exit loudly if the file is empty - Delete dumps older than your retention window
- Write to a log you actually check
How often should you dump? The MassiveGrid n8n backup guide gives sensible defaults that match what we see recommended across self-hosting communities:
- Light use (under 20 workflows, personal): daily, keep 7 days
- Medium (20 to 100 workflows, a team depends on it): every 6 hours, keep 14 days
- Heavy (100+ workflows, business-critical): every 2 hours, keep 30 days
The frequency sets your recovery point objective: how much work you can lose. A typical n8n database with 50 workflows and a week of execution history compresses to 10 to 50 MB, so storage is not the constraint. Backup frequency is nearly free; data loss is not.
One honest caveat from the PostgreSQL docs: pg_dump is generally not the right tool for regular backups of large or complex production databases, where continuous archiving and point-in-time recovery are better. For a single-VPS n8n deployment, which describes most self-hosted instances, pg_dump is adequate and simple. If your n8n database grows into tens of gigabytes, revisit this choice.
Export workflows and credentials with the CLI
The database dump is your primary backup. The n8n Server CLI export is your portable secondary one:
n8n export:workflow --backup --output=backups/workflows/
n8n export:credentials --backup --output=backups/credentials/
The --backup flag expands to --all --pretty --separate, writing each workflow and credential as a separate readable JSON file. These files are useful for version control and for moving workflows between instances.
Three gotchas, all real:
- Use different output directories for the two commands. There is a confirmed bug, GitHub issue #37814, where
import:credentials --separateaborts with a SQLite constraint error if the input directory also contains workflow JSON files. It tries to import a workflow as a credential, fails, and the whole import aborts. Separate directories avoid it completely. - In Docker, a
backups/directory inside the container is not persisted. Only the.n8nfolder is in a volume. Bind-mount a host directory for exports, or copy the files out withdocker cpbefore recreating the container. - Know what the CLI export does not contain: users and their roles, execution history, variables, and instance settings including the encryption key. It is enough to move workflows between instances, not enough to recover an instance.
A note on versions: in n8n 2.0, the old active/inactive toggle was replaced by a publish/unpublish model. Imported workflows are unpublished by default, so plan to republish them after a restore, either in the UI or with the CLI.
Execution data is not backed up, and n8n deletes it anyway
Execution history sits in the database, so it rides along in your pg_dump. But do not treat backups as an audit trail, because n8n prunes execution data on a rolling basis by default. Per the executions environment variables:
EXECUTIONS_DATA_PRUNEdefaults totrueEXECUTIONS_DATA_MAX_AGEdefaults to 336 hours, which is 14 daysEXECUTIONS_DATA_PRUNE_MAX_COUNTdefaults to 10,000 executions
So even a perfect backup restore gives you at most the execution history that survived pruning at backup time. If you need execution records for compliance, client billing disputes, or debugging patterns over months, archive them separately before pruning: export via the n8n API or a scheduled workflow that writes execution summaries to a warehouse or even a spreadsheet. Restoring old execution data from a database dump is possible but painful, because pg_restore of one table into a live instance is fiddly.
Store backups off the server
Backups on the same disk as n8n protect against accidental deletion and bad updates. They do nothing against disk failure, a datacenter outage, or ransomware. Offsite storage is not optional for anything business-critical.
rclone is the practical tool: one binary that syncs to Backblaze B2, S3, Google Cloud Storage, Azure Blob, and dozens of other backends. The command is simple:
rclone sync ~/n8n-backups b2:your-n8n-backup-bucket --transfers 4 --min-age 1m
Note that sync makes the destination identical to the source, modifying only the destination. Run it as a second cron job 30 minutes after the backup, and protect the rclone config file (it holds your storage credentials) with the built-in configuration password.
The cost is trivially small. Backblaze B2 starts at $6.95 per TB per month, includes the first 10 GB of storage free, and charges nothing for egress up to three times your stored volume. Thirty days of daily 50 MB dumps is 1.5 GB. Your offsite n8n backups cost effectively zero dollars per month. If a vendor quotes you real money for this, they are charging for the software around it, not the storage.
Also copy the .n8n folder offsite. An encrypted tarball of it plus your docker-compose.yml and .env means a brand-new VPS can become your n8n server in under an hour.
Test the restore: the quarterly drill
A backup you have never restored is a hypothesis. Run this drill quarterly, on a throwaway VPS or a local Docker setup:
- Spin up a fresh environment. Same n8n version as production if you can; at minimum, a recent one.
- Restore the database. Create the database, then
pg_restorethe latest dump. - Restore the
.n8nfolder, or setN8N_ENCRYPTION_KEYto the value from your password manager. This is the step where you find out whether your key backup is real. - Restore deployment config: environment variables for the database connection and any external storage settings.
- Start n8n and open the UI. Log in, open a credential, and confirm it decrypts. Then run one workflow that calls an external API.
- Time the whole drill. That time is your recovery time objective. If it takes 90 minutes the first time, it will take 20 the third time, and the third time might be the real one.
If you are restoring from CLI exports onto a fresh instance instead of a full database restore, complete the owner setup screen first: the import commands need an existing user, and imported credentials need an owner. Exports keep their original IDs, so re-importing into an instance that already has those items overwrites them.
Common mistakes
- Backing up the database but not the encryption key. The most expensive mistake on this list. Everything restores and nothing decrypts.
- Writing CLI workflow and credential exports to the same directory. Restores abort thanks to the known import bug. Use two directories.
- Backing up inside the Docker container. The container is ephemeral. Only volumes persist.
- Copying the SQLite file while n8n is running. Inconsistent backups that fail at restore time. Stop n8n first, use a snapshot tool, or move to PostgreSQL.
- Never checking whether the cron job actually ran. An empty dump file and a silent cron failure look identical from a distance. Log, check file sizes, and alert on failure.
- Assuming execution history is archived. Pruning deletes it after 14 days by default.
- Skipping the restore drill. Untested backups fail at the worst moment, for reasons you did not predict.
When this setup is the wrong choice
This guide assumes a single self-hosted instance where a few hours of downtime and up-to-the-last-backup data loss are acceptable. It is the wrong choice when:
- You cannot tolerate any data loss. You need PostgreSQL point-in-time recovery with WAL archiving, not nightly pg_dump.
- You cannot tolerate downtime. You need queue mode with redundant workers and multi-main setup, which is a scaling and availability project, not a backup project. Our guide to scaling self-hosted n8n with queue mode covers what breaks first when you go down that road.
- Nobody owns maintenance. A backup system that nobody checks is worse than none, because it manufactures confidence. If your team will not run the quarterly drill, paying for n8n Cloud or a managed deployment is the honest answer. Cloud plans handle infrastructure and upgrades for you; the trade-off is per-execution pricing and less data control, which we break down in our n8n, Zapier, and Make comparison.
Frequently asked questions
Is the n8n CLI export enough to restore my instance?
No. The CLI export contains workflows and credentials only. It does not include users, execution history, variables, or instance settings. For full recovery you need the .n8n folder and, if you use PostgreSQL, a database dump, plus the encryption key.
What happens if I lose the n8n encryption key? Every stored credential becomes permanently unreadable. Workflows and the UI still work, but no workflow can authenticate with any external service until you re-enter every credential by hand. Store the key in a password manager and a second location today.
Should I use SQLite or PostgreSQL for n8n? SQLite is fine for personal use and small setups, but you must stop n8n before backing up the database file or risk a corrupt copy. PostgreSQL allows consistent backups while running via pg_dump, which is why it is the right choice for anything a team depends on.
How much does offsite n8n backup storage cost? Effectively nothing at typical scale. A month of daily database dumps for a mid-size instance is around 1.5 GB. Backblaze B2 includes the first 10 GB of storage free and starts at $6.95 per TB per month beyond that.
How often should I test restores? Quarterly at minimum, and after any major change: a version upgrade, a move from SQLite to PostgreSQL, or a server migration. Time the drill so you know your real recovery time.
Does n8n Cloud need this backup setup? No. n8n Cloud is managed by n8n, including infrastructure and uptime monitoring. The backup burden described here applies to self-hosted instances, where you are the infrastructure team.
Where to go from here
Backups are the part of self-hosting that only proves themselves on the worst day, and the whole system above costs a few hours to build and nearly nothing to run. If you want the same rigor applied across your whole stack, our guide to backing up a self-hosted business stack and proving it restores covers the other applications. And if you would rather hand the whole thing, n8n, backups, monitoring, updates, to a team that does this for a living, that is exactly what our business automation service and managed open-source stack are for.
About AI Agents Plus Editorial
AI automation expert and thought leader in business transformation through artificial intelligence.



