
An agency we work with lost four hours of an afternoon last spring because someone opened a live lead-routing workflow, dragged a node to tidy up the canvas, accidentally detached a branch, and hit save. No error. The workflow just quietly stopped sending half the leads to the CRM. There was no history to roll back to, because the instance was on the Pro plan and nobody had set up backups.
You do not need n8n's Business plan to get real version control. Native Git source control is locked to Business and Enterprise, but a scheduled workflow that reads the n8n public API and writes each workflow as JSON to a private GitHub repository gives you the parts that actually matter — a full history, readable diffs, and a restore path — for the cost of one extra workflow. What you give up is the push and pull buttons inside the n8n UI, the protected-instance lock, and native environment branching.
We run this setup on six client instances. The largest has 212 workflows and backs up every three hours. Here's exactly what the paid feature does, what the DIY version does, and the four things that will bite you if you build it carelessly.
What n8n's Built-In Source Control Actually Does
n8n's source control connects an instance to a Git repository and gives you push and pull inside the app. It is worth understanding precisely, because a lot of people assume it is more than it is.
- Push saves workflows, tags, and stubs. According to n8n's own documentation, a push writes a copy of your workflows and tags, plus credential and variable stubs, to Git. Secret values never leave the instance. You can select which workflows go in a given push.
- Commit and push are one action. There is no local staging step the way there is on your laptop. You pick the resources, write a message, and it goes to the remote.
- Pull overwrites. Pulling brings workflows, tags, and variables down from Git and overwrites anything on the instance that was not pushed first. This is the single most common way teams lose work with the feature turned on.
- There is no review step. The docs say it outright: source control in n8n does not support a pull-request-style review and merge process unless you do that outside n8n, in your Git provider. So the "we'll review changes before they hit prod" story requires the same manual discipline either way.
- Environments are branches. Each n8n instance points at one branch. Dev points at dev, prod points at main. You promote by merging the branch in GitHub and pulling on the target instance.
- Protected instances stop editing. An optional setting prevents users editing source-controlled resources on that instance. This is the genuinely valuable bit, and it is the one thing you cannot replicate with a backup workflow.
Setup is a repository URL, a branch, and either an SSH deploy key or an HTTPS personal access token, entered under Settings and Environments.
What It Costs, and Why Most Agencies Skip It
Git-based version control and multiple environments start at the Business plan, which n8n lists at around 667 euros per month. Enterprise includes it too, at custom pricing. Starter (about 20 euros) and Pro (about 50 euros) do not, and neither does the self-hosted Community edition — which is where most of the agencies we talk to are running, for reasons we covered in our breakdown of self-hosted n8n versus n8n Cloud for agencies.
That jump — roughly 50 euros to 667 euros — is not a pricing objection, it's a category change. An agency running client automations on a 40-euro VPS is not going to add 8,000 euros a year for a push button. So they either go without version control entirely, which is what happened to the client above, or they build it.
Worth noting separately: the licensing question around running n8n for clients is a different topic from the plan question, and we wrote about n8n's commercial license for agencies if that's the part you're unsure about.
The Git Backup Workflow We Actually Run
The whole thing is one n8n workflow. It reads its own instance through the public API and writes to GitHub. Six nodes, plus a Code node doing the normalising.
The node order:
- Schedule Trigger — every three hours on active client instances, daily on ones that barely change. Pick the interval by how much work you're willing to lose, not by what sounds tidy.
- HTTP Request to
GET /api/v1/workflows— with theX-N8N-API-KEYheader. This returns a paginated list. FollownextCursoruntil it comes back empty. The list response is a summary, so you need step 3. - HTTP Request to
GET /api/v1/workflows/{id}— per workflow, to pull the full node graph, connections, settings, and pinned data. - Code node — normalise. Sort object keys, pretty-print with two-space indentation, and delete the volatile fields. This is the step everyone skips and everyone regrets.
- HTTP Request to the GitHub Contents API —
GET /repos/OWNER/REPO/contents/workflows/{id}.jsonto grab the existingsha, thenPUTthe same path with base64-encoded content and thatsha. GitHub rejects updates without it. - Error branch — route failures to Slack or email. A silent backup failure is worse than no backup, which is the same argument we make about n8n error handling and monitoring generally.
If you'd rather not build it from scratch, n8n's template library has several backup templates that follow this shape. They're a fine starting point. We rewrite the Code node in every one of them, because none of them normalise aggressively enough.
The Four Things That Bite You
These are the failures we've actually hit, not hypotheticals.
1. Noisy diffs make the history worthless. Raw n8n workflow JSON includes updatedAt and the x/y pixel coordinates of every node. Move one node two pixels and you get a 40-line diff. After a week of that, nobody reads the history and the whole exercise is theatre. Strip updatedAt, round or drop position, and sort keys so the ordering is stable across exports. Our diffs now show two or three lines when someone changes an expression, which is the entire point.
2. Naming files by workflow name orphans them. If lead-router.json gets renamed to lead-router-v2 in the UI, a name-keyed backup writes a brand new file and leaves the old one sitting there forever. Six months later the repo has 340 files for 212 workflows and you can't tell which are live. Key the filename on the immutable workflow ID and put the human name in the commit message.
3. Hardcoded secrets end up in the repository. Workflow JSON references credentials by ID and name, so real credential secrets stay out. But an API key someone pasted directly into an HTTP Request header, or a token sitting in a Code node string, is part of the node graph and gets committed in plain text. Keep the repo private and run a secret scanner over it. We found a live Twilio auth token this way on a client instance in its second week of backups.
4. A restore is an import, not a merge. Pushing JSON back into n8n creates or replaces a workflow; it does not reconcile it with what's there. Restored workflows come back inactive, and their credential references only resolve if credentials with matching IDs exist on the target instance. That last part is what turns a "we have backups" into "we have backups that don't run." Test the restore on a scratch instance before you need it in anger — same principle as testing n8n AI agents before production.
How to Promote Dev to Prod Without Environments
Two instances, one repository, two folders. The dev instance backs up to dev/workflows/, prod to prod/workflows/.
Promotion is a second small workflow with a manual trigger: it reads a workflow ID from the dev folder in Git, POSTs it to the prod instance's /api/v1/workflows endpoint (or PUTs to an existing ID), and leaves it inactive. A human opens prod, looks at it, and activates it.
That deliberate manual gate is not a limitation we're apologising for. It's roughly what the native feature gives you anyway, since n8n has no in-app review step either. The two rules that make it work:
- Credential names and IDs must match across both instances. Create credentials on prod first, with the same names, before the first promotion. Otherwise every import lands with an unresolved credential and someone has to click through each node.
- Never promote an active workflow directly. Import inactive, verify, then activate. On a busy prod instance this also avoids the surprise of a schedule trigger firing the moment the import lands — which matters more if you're running queue mode with multiple workers.
When You Should Actually Pay for Business
We're not anti-Business. There are three situations where the DIY setup is the wrong answer:
- You need the protected instance. If non-technical staff have prod access and you need the platform itself to stop them editing, no backup workflow substitutes for that. This is the strongest argument for the paid feature by a distance.
- You have compliance requirements that name SSO or log streaming. Those live on the same tiers. If you're buying them anyway, source control is already in the box.
- Your team is large enough that ad-hoc discipline fails. Two people can follow a promotion checklist. Twelve cannot. At that size the in-UI guardrail earns its price.
For everything below that — a two to ten person agency running client automations on self-hosted n8n — the backup workflow is a Tuesday afternoon of work and it covers the disaster you're actually scared of.
Where to Start
Set the backup workflow up first, before you think about environments. Versioned history and a tested restore path solve the four-hours-lost-on-a-Tuesday problem. Dev-to-prod promotion solves a nicer problem you can get to later.
And genuinely, do the restore test. Every agency we've onboarded that already had "backups" had never once restored from them. Two of them had backups that would not have worked.
If you're running client automations on n8n and you're not sure what would happen if someone deleted the wrong thing today, we'll look at it with you. Get a free automation audit — we'll review your workflows, your failure handling, and your restore path, and tell you plainly what's fragile.