FlowKit

Separating development and production in n8n: clean dev/prod environments

Published 26 July 2026 · 6 min read

Editing an n8n workflow directly in production is like changing a tire on a moving car. A node left half-reconfigured while a webhook keeps receiving real calls, a test "Execute Workflow" that sends a real email to a real customer, an IF branch flipped for a quick experiment that routes data the wrong way: every click in the editor acts immediately on the live system. As long as your workflows are decorative, the risk stays theoretical. The moment they handle orders, customer emails, or payments, it becomes a matter of time. The answer is the same one software development adopted long ago: separate the place where you experiment from the place where things run.

The concrete problem with "everything in prod"

Three scenarios come up over and over for people working on a single instance:

  • The webhook that breaks mid-edit. Opening an active workflow to modify it means risking an intermediate save in an inconsistent state — the external provider keeps calling the URL, and executions fail silently for the entire editing session.
  • Real data altered by tests. A "just to see" test run on a workflow wired to a CRM or a production database writes into the real data. There is no undo button for an overwritten Airtable row or an email that already went out.
  • A polluted execution history. Test runs mix with real runs, and diagnosing an actual incident becomes a needle-in-a-haystack search — a problem that surfaces as soon as you set up error handling with an Error Workflow: alerts also fire on the deliberate failures of your tests.

The minimal approach: duplicating on the same instance

The first line of defense, available in thirty seconds, is to duplicate the workflow: the copy becomes the inactive "working copy" you experiment on freely, while the original keeps running. Two n8n tags, dev and prod, let you filter the list and see at a glance which is which.

It's better than nothing, and sometimes enough for solo use on low-stakes workflows. But the limits are structural:

  • Same credentials. The working copy uses the same API keys as production. A test sends real Slack messages, creates real invoices, writes to the real bucket.
  • Same webhook URLs. Two workflows can't listen on the same production webhook path; the copy uses the test URL (/webhook-test/), which only stays active while you're manually listening — you never really test real-world conditions.
  • The risk of activating the wrong version. One activation toggle clicked on the copy instead of the original (or the reverse), and two workflows process the same events in duplicate — or none does.

This approach is a band-aid, not an architecture. As soon as your workflows matter, real separation becomes non-negotiable.

The clean approach: two separate instances

The robust solution fits in one sentence: two Docker containers, two PostgreSQL databases, two subdomains. One n8n-dev.yourdomain.com instance to build and break, one n8n.yourdomain.com instance to run. On a single server, one docker-compose.yml per environment (or a single file with two services) is enough:

services:
  n8n-dev:
    image: n8nio/n8n
    restart: unless-stopped
    environment:
      - N8N_HOST=n8n-dev.yourdomain.com
      - WEBHOOK_URL=https://n8n-dev.yourdomain.com/
      - N8N_ENCRYPTION_KEY=${DEV_ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres-dev
      - DB_POSTGRESDB_DATABASE=n8n_dev
    ports:
      - "5679:5678"
    volumes:
      - n8n_dev_data:/home/node/.n8n

  postgres-dev:
    image: postgres:16
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n_dev
    volumes:
      - pg_dev_data:/var/lib/postgresql/data

Production follows the same pattern with n8n.yourdomain.com, its own n8n_prod database, and its own N8N_ENCRYPTION_KEY. The reverse proxy (Traefik or Caddy) routes each subdomain to the right container. Two separate databases also mean two backup strategies: only production justifies a rigorous PostgreSQL backup routine; dev can get away with much less.

A non-trivial bonus: dev becomes the natural testing ground for version upgrades. Update n8n-dev first, verify that the critical workflows still pass, then update prod — exactly the approach from our guide on updating n8n under Docker without breaking anything.

Separate credentials per environment

The rule is absolute: production credentials never set foot on the dev instance. Each environment gets its own:

  • Stripe: test mode exists precisely for this — sk_test_… keys in dev, live keys in prod only.
  • Slack / email: a #n8n-tests channel and a dedicated mailbox in dev, rather than the customer channel and the main domain.
  • Third-party APIs: most serious providers offer a sandbox environment; when they don't, a separate free account does the job.

This separation mechanically limits the blast radius of a test gone wrong, and it lines up with the principles in our guide on securing credentials and API keys in n8n: the fewer sensitive secrets an experimental environment holds, the less a leak or a slip-up costs. Since each instance has its own N8N_ENCRYPTION_KEY, credentials have to be entered separately on each side anyway — a constraint that works in your favor.

Parameterize what changes with environment variables

A workflow that hardcodes https://api.yourservice.com or the name of a production bucket will need editing at every promotion — the perfect recipe for a missed step. The fix: externalize everything that differs between environments into environment variables, injected through the environment section of your docker-compose file and read inside nodes with an expression ({{ $env.API_BASE_URL }}). API base URL, S3 bucket name, Slack channel ID: the exact same workflow JSON then runs identically on both sides — only the context changes.

Promoting a workflow from dev to prod

Going live is not a copy-paste, it's a procedure. The most reliable pivot is a Git repository: JSON export from dev, commit, import into prod — the full mechanism (the export:workflow / import:workflow CLI, the script, the Docker case) is covered in our guide on versioning n8n workflows with Git. Along the way, Git gives you change review and instant rollback — two things copy-paste will never provide.

The promotion checklist, to run through every single time:

  1. Export the workflow from dev and commit it to Git;
  2. Import it into the production instance;
  3. Remap credentials: every node must point to production credentials, not orphaned references;
  4. Update webhook URLs with external providers (Stripe, Typeform, GitHub…) to point to n8n.yourdomain.com;
  5. Attach the production error workflow in the workflow settings;
  6. Activate — and verify the first real execution.

Test before you promote

Promotion is only the last step; confidence is built beforehand. For webhook-triggered workflows, replaying real calls in dev (realistic payloads, signatures, error cases) follows the techniques from our guide on testing n8n webhooks locally. For workflows that embed an LLM, a manual "looks good" check isn't enough: systematically evaluated example sets, as described in our article on evaluations for AI workflows in n8n, turn promotion from a gamble into a measured decision.

This discipline isn't an engineer's whim: it's exactly what Lianping Chen documents in his industrial experience report « Continuous Delivery: Huge Benefits, but Challenges Too », published in IEEE Software in 2015: continuous delivery significantly reduces release risk and speeds up feedback, but those benefits only come at the price of a real investment in tooling and team discipline. Two n8n instances, a Git repository, and a checklist are precisely that investment — at the scale of a small business rather than a software giant.

Where this connects to your FlowKit packs

The workflows shipped in the AI Inbox Pack (€79), the RAG Assistant Pack (€119), and the Compliance & Audit Pack (€149) fit naturally into this setup: import them into the dev instance first, adapt the prompts and test credentials, run trials on dummy data, then promote to prod through the checklist above. It's the safest way to customize a pack without ever exposing your real data to a workflow still being broken in. The Complete FlowKit Bundle (€269 instead of €347) covers all three families with the same logic: JSON files ready to travel from dev to prod, exactly like your own workflows.

FAQ

Frequently asked questions

Can I run an n8n dev environment on the same instance as production?

You can, by duplicating the workflow as an inactive « working copy » with dev/prod tags, but that approach has structural limits: same credentials, same webhook URLs (except for the -test suffix), and a permanent risk of activating or editing the wrong version. It works as a stopgap for solo use; it doesn't hold up once workflows touch real data or multiple people are involved.

Do I need two servers to run two n8n instances?

No. Two Docker containers on the same machine, each with its own PostgreSQL database, port, and subdomain (n8n-dev.yourdomain.com and n8n.yourdomain.com), are more than enough. The reverse proxy (Traefik or Caddy) routes to the right container. A dedicated server for production only becomes relevant when execution volumes or availability requirements grow.

How do I move a workflow from dev to production without breaking things?

By following a systematic promotion checklist: export the JSON from dev (ideally through a Git repository acting as the pivot), import it into prod, remap credentials to production accounts, update webhook URLs with external providers, attach the error workflow, then activate. Every skipped step is a silent outage waiting to happen.

Can credentials be shared between the two environments?

No, never for services that touch real data or real money. The dev environment should use test API keys (Stripe test mode, provider sandboxes), a test Slack channel, and a dedicated mailbox. Each n8n instance also has its own N8N_ENCRYPTION_KEY, so credentials are recreated separately on each side anyway.

Bundle FlowKit Complet

€269