🛠️Field notes

Self-hosting n8n: what actually broke when we moved a production instance

In September 2026 I moved Otimiz's production n8n instance, about 130 workflows and every credential behind them, onto a new server. On paper that's a database export and a restore. In practice it surfaced seven things that don't show up in n8n's docs until they've already cost you something. Here's the honest list: what happened, how it got caught, and the rule I run by now.

Key takeaways

  • n8n's encryption key isn't stored with your workflows by default. Lose the server without it and every credential is unrecoverable, even though the workflows survive.
  • A community-installed node lives outside the database. Move servers without reinstalling it and it fails silently at runtime while looking correct everywhere you'd normally check.
  • An HTTP 200 on save proves n8n accepted the file, not that it will run.
  • A republished workflow can keep running its old logic until you deactivate and reactivate it.

Lesson 1: the encryption key is not part of your backup by default

n8n encrypts every stored credential (API keys, OAuth tokens, passwords) with a single instance-wide key. We had never set that key as an environment variable, so n8n had generated one for us and written it into a config file inside the running container, not anywhere we'd normally think to back up.

What would have happened: if that server's disk had gone with no separate copy of that file, the workflow definitions would have survived in our export, but every credential referenced inside them would have been permanently unrecoverable. Not hard to recover. Gone.

How it was caught: by deliberately going looking for it before the move, not by losing it. We pulled the key off the running container and stored it alongside the database export before touching anything.

The rule now: treat the encryption key as a first-class secret with its own backup, checked before any server move, never assumed to travel with the database. If you've never gone looking for yours, you likely don't have a copy either.

Lesson 2: a community node package is not in your database

This is the one that cost us the most, and it hid for 13 days before anyone noticed. We use a community-maintained node for one of our email-sending integrations. Community nodes are installed as a package alongside n8n, not stored as data inside the workflow database.

The server move restored every workflow and credential correctly. What it did not restore was that installed package, because nobody had put the node directory on the migration checklist. Every workflow using that integration looked completely normal (correct nodes, correct credential reference, correct configuration) and failed the instant it actually tried to run, with an error naming a credential type n8n no longer recognised.

What it cost: ten production workflows across roughly forty nodes, including one that sends a paying customer their delivery email after checkout. Those flows saw very little real traffic in that window, and no lost message is proven. That's luck, not design.

How it was caught: by accident, when a real webhook call exercised the broken path and threw an error while someone happened to be watching.

Why it stayed hidden so long: three things stacked. The failure only happens at runtime, so the workflow saves and reads clean. Execution history gets pruned automatically, so there was no error log sitting around to stumble over. And in the workflow that had real traffic, the alert step sat downstream of the failing node, so the failure silenced its own alarm.

The rule now: any community node package is infrastructure, not data. It gets reinstalled explicitly on any server move or container rebuild, as its own line on the checklist.

Lesson 3: draft and active are two different things

n8n stores a workflow's configuration twice: once as the editable draft you see on the canvas, and once as the version that's actually executing. Saving a change updates the draft. The live trigger keeps running the old version until you deactivate the workflow and reactivate it.

That gap means a fix can look complete, pass a review, and still not be running. Anyone asserting "this is fixed" off the saved workflow, rather than the running version, can be confidently wrong.

The rule now: after any change to something already live, deactivate and reactivate before treating it as shipped, and check the running version specifically.

Lesson 4: a save that returns success doesn't mean the workflow can run

n8n will accept and save a workflow whose expressions don't actually parse. We found a workflow that saved successfully and would have thrown the first time its schedule fired, because of a raw newline sitting inside what was supposed to be a single-line JavaScript string in a code step.

How it was caught: by reading the file at byte level rather than trusting that a successful save meant a working workflow.

The rule now: a 200 response on save proves the file was accepted, nothing more. For anything that matters, execute it once for real or inspect it at byte level before calling it done.

Lesson 5: pin the version, or a restart can rewrite your database for you

Our production instance runs a specific, pinned n8n release rather than the :latest image. That decision mattered more than almost anything else on this list: pulling a newer image at restore time would have triggered n8n's own database migrations on first boot, automatically and irreversibly, whether we were ready for that schema change or not.

The honest trade-off: staying pinned means you fall behind. Our instance is now dozens of minor versions behind current. That's a deliberate, managed choice, and moving forward happens on our schedule, with a snapshot taken first, not when a container restart decides.

Pin the version. :latest in a production container is a promise that the next restart can quietly and permanently change your database, and you don't get to vote on when that restart happens.

The rule now: pin explicitly, upgrade deliberately with a snapshot first, and never let a container recreation or a fresh pull decide your schema version.

Lesson 6: execution history will fill your disk if you let it

n8n logs every execution, and unless you turn pruning on, it keeps them. On our old instance, at roughly 190 executions a day with pruning off, the database was growing by around 430 MB a day, almost entirely execution data rather than configuration. That's an unbounded growth curve for data that has almost no value once an execution is a few weeks old.

The rule now: execution pruning is on from day one of any new instance, with a fixed retention window (we run 14 days), so disk usage stays flat instead of becoming next quarter's emergency.

Lesson 7: webhook authentication is opt-in, and it's easy to forget

n8n does not require authentication on a webhook trigger by default. You can build, test and ship a webhook-triggered workflow without ever being prompted to think about who else could call it: anyone who finds the URL can POST to it.

One of ours had exactly this problem on a workflow that could write to an outbound-messaging blocklist. We closed it by moving the endpoint to a long, unguessable path with an explicit authentication check ahead of anything sensitive, rather than relying on the URL simply not being known.

The rule now: every new webhook trigger gets an explicit authentication decision at build time, not the default. "Nobody will guess this URL" is not a security control.

The checklist

Run through this on any n8n move, rebuild or version upgrade:

  1. Back up the encryption key as its own artifact, separate from the database export.
  2. List every community node package in use and reinstall each one explicitly on the new instance.
  3. Execute one real workflow per integration after any move, rather than counting workflows and credentials as proof anything works.
  4. Deactivate and reactivate any workflow you've edited, and verify against the running version, not the saved draft.
  5. Pin the version explicitly and never let a container recreation pull :latest. Upgrade deliberately, with a snapshot first.
  6. Turn on execution pruning with a fixed retention window before real traffic starts.
  7. Audit every webhook trigger for authentication. Treat "no auth configured" as the default failure mode to look for.

If you're weighing n8n Cloud against self-hosting in the first place, the plan prices and the running cost are in our n8n pricing guide. If you'd rather have someone who has already made these mistakes build and run it for you, that's what our n8n development service is for.

Bastien Daumas
Bastien Daumas
Founder, Otimiz

Ex English-French translator who built a translation SaaS, automated the backend with no-code, and turned that into an AI automation agency. Based near Nice, working with B2B clients globally. No false promises, just fewer repetitive tasks and concrete results.

FAQ

Self-hosting n8n, answered

Not inherently, but the risks are different. Cloud puts the operational failure modes on n8n's team. Self-hosting puts them on you: backups, version upgrades, and infrastructure-level dependencies like community node packages and the encryption key. None of these are hard problems once you know to look for them, which is why a checklist matters more than instinct here.

It's the single key n8n uses to encrypt every credential stored in your instance: API keys, OAuth tokens, passwords. If you never set it explicitly, n8n generates one inside the running container. If that container or its volume is lost without a separate backup of the key, every stored credential becomes permanently unrecoverable, even though the workflow logic itself is fine.

Because community-maintained nodes are installed as software packages alongside n8n, not stored as data in the workflow database. A database restore brings back your workflows and credentials, but not a package that was never part of that database. The workflow looks normal in the editor and fails only when it actually tries to run.

No. n8n can accept and save a workflow whose expressions don't parse and still return a normal success response. That only proves the file was written. For anything you rely on, execute it for real or check the file itself before treating a successful save as proof it works.

Not ready to talk yet? Get a free written automation audit: three automations worth building for your business, with rough hours on each. No call. Request your audit.

📬Contact

Want n8n run by someone who has already made these mistakes?

Book a free audit. We will map your processes and tell you what to automate first, and how to host it safely.

Book My Free Audit