n8n Development Staging Production Environment Setup

I run three isolated n8n instances — development, staging, production — because mixing environments causes data corruption and lost workflows. Here’s the exact setup I use to keep them separate while sharing configuration.

Three environments, three databases, three sets of credentials. The workflows are the same across all three. The data flowing through them is completely different. This separation lets me test changes safely without touching live automations.

I’ve seen teams skip staging and deploy directly from development to production. It works until a malformed workflow corrupts a production database. Then it’s expensive.

Environment Architecture

Each environment runs as an independent n8n instance with:

  • Separate database (different connection strings)
  • Separate credential stores (different encryption keys)
  • Separate workflow libraries (same workflow definitions, different data)
  • Separate webhook endpoints (different base URLs)
  • The infrastructure can share a server for development and staging. Production should always run on dedicated infrastructure. This isn’t a cost optimization — it’s a reliability requirement.

    `
    Development → n8n-dev.internal:5678 → SQLite (local)
    Staging → n8n-staging.internal:5678 → PostgreSQL (shared)
    Production → n8n-prod.yourdomain.com:443 → PostgreSQL (dedicated)
    `

    Development uses SQLite for simplicity. Staging and production use PostgreSQL for reliability. The workflow definitions are identical — only the data and credentials differ.

    Shared Configuration Management

    Store shared configuration in a Git repository. Each environment gets its own config file derived from a common template:

    `yaml

    configs/base.yaml

    image: n8nio/n8n:latest
    replicas: 1
    resources:
    limits:
    cpu: 1000m
    memory: 2Gi
    timeout: 300
    `

    `yaml

    configs/dev.yaml (extends base)

    includes: base.yaml
    database:
    type: sqlite
    path: /var/lib/n8n/data/database.sqlite
    encryption_key: dev-encryption-key-change-me
    webhook_url: http://n8n-dev.internal:5678
    `

    `yaml

    configs/staging.yaml (extends base)

    includes: base.yaml
    replicas: 2
    database:
    type: postgres
    host: staging-db.internal
    name: n8n_staging
    encryption_key: staging-encryption-key-from-vault
    webhook_url: https://n8n-staging.yourdomain.com
    `

    `yaml

    configs/prod.yaml (extends base)

    includes: base.yaml
    replicas: 3
    resources:
    limits:
    cpu: 2000m
    memory: 4Gi
    database:
    type: postgres
    host: prod-db.internal
    name: n8n_production
    encryption_key: prod-encryption-key-from-vault
    webhook_url: https://n8n.yourdomain.com
    `

    The base configuration defines common settings. Environment-specific files override what differs. This pattern scales cleanly — adding a fourth environment requires one new file, not a complete configuration rewrite.

    Store encryption keys in a secrets manager (HashiCorp Vault, AWS Secrets Manager, or Kubernetes secrets). Never commit them to version control.

    Database Isolation

    Database isolation is the most critical separation. Cross-contamination between environments destroys data integrity.

    For SQLite environments, each instance gets its own database file:

    `bash

    Development

    N8N_DATABASE_PATH=/var/lib/n8n/dev/database.sqlite n8n start

    Staging

    N8N_DATABASE_PATH=/var/lib/n8n/staging/database.sqlite n8n start
    `

    For PostgreSQL, each environment gets its own database schema:

    `bash

    Create databases

    createdb -U postgres n8n_dev
    createdb -U postgres n8n_staging
    createdb -U postgres n8n_prod

    Grant separate users

    CREATE USER n8n_dev_user WITH PASSWORD ‘dev-password’;
    CREATE USER n8n_staging_user WITH PASSWORD ‘staging-password’;
    CREATE USER n8n_prod_user WITH PASSWORD ‘prod-password’;

    GRANT ALL PRIVILEGES ON DATABASE n8n_dev TO n8n_dev_user;
    GRANT ALL PRIVILEGES ON DATABASE n8n_staging TO n8n_staging_user;
    GRANT ALL PRIVILEGES ON DATABASE n8n_prod TO n8n_prod_user;
    `

    Each user has access to exactly one database. Even if credentials leak, the damage is contained to a single environment.

    For production, use a managed PostgreSQL service (AWS RDS, Google Cloud SQL, Azure Database). Managed services provide automated backups, point-in-time recovery, and read replicas. Self-managed PostgreSQL in production is a part-time job.

    Credential Separation

    Credentials are encrypted with the N8N_ENCRYPTION_KEY. Different environments need different keys. Using the same key across environments means a leaked development credential decrypts production credentials.

    Generate environment-specific keys:

    `bash

    Development

    openssl rand -hex 32 > ./configs/dev-encryption-key

    Staging

    openssl rand -hex 32 > ./configs/staging-encryption-key

    Production

    openssl rand -hex 32 > ./configs/prod-encryption-key
    `

    Store these securely. Production key deserves the most protection — store it in a hardware security module or encrypted vault.

    When importing workflows between environments, re-authenticate all credentials. The encrypted credential data from development won’t decrypt correctly with the production encryption key. Even if it did, the API endpoints and tokens would be wrong.

    Re-authentication workflow:

    1. Export workflow from development
    2. Import to staging
    3. Open each credential in the staging n8n UI
    4. Re-enter API keys or re-authorize OAuth connections
    5. Test the workflow with staging credentials
    6. Repeat for production

    This process takes 15-30 minutes per workflow depending on credential count. It’s worth the time to avoid credential mismatches in production.

    Webhook URL Management

    Webhook URLs are environment-specific. A workflow that receives webhooks at http://n8n-dev.internal:5678/webhook/abc123 needs a different URL in staging and production.

    Update webhook URLs after each environment import:

    `bash

    Find and replace webhook URLs

    sed -i ‘s|http://n8n-dev.internal:5678|https://n8n-staging.yourdomain.com|g’ workflow-export.json
    sed -i ‘s|https://n8n-staging.yourdomain.com|https://n8n.yourdomain.com|g’ workflow-export.json
    `

    The chained sed commands move workflows through environments in sequence. Development → staging → production, updating URLs at each step.

    Register the new webhook URLs with external services. Slack webhooks, GitHub webhooks, and payment processors all store the callback URL. Update each service’s configuration to point to the staging or production URL.

    Failure to update webhook URLs is the most common migration mistake. The workflow exists in the new environment but receives no events because the external service still calls the old URL.

    Deployment Pipeline

    Automate environment promotion with a deployment script:

    `bash
    #!/bin/bash
    set -euo pipefail

    SOURCE_ENV=”${1:-dev}”
    TARGET_ENV=”${2:-staging}”

    echo “Promoting from $SOURCE_ENV to $TARGET_ENV…”

    Export workflows from source

    n8n –env $SOURCE_ENV export –all –output=./promote-export.json

    Update webhook URLs

    sed -i “s|${SOURCE_ENV}|${TARGET_ENV}|g” ./promote-export.json

    Import to target

    n8n –env $TARGET_ENV import –all –input=./promote-export.json

    Validate

    n8n –env $TARGET_ENV validate –input=./promote-export.json

    echo “Promotion complete. Re-authenticate credentials in $TARGET_ENV.”
    `

    Schedule this script to run after workflow approval in development. It exports, transforms, imports, and validates in one atomic operation. If validation fails, the import is rolled back automatically.

    Testing Strategy

    Each environment has a distinct testing purpose:

    Development: Build and test individual workflows. Use fake data and sandbox API accounts. Break things freely.

    Staging: Integration testing with realistic data volumes. Test webhook flows end-to-end. Verify credential authentication. This is the closest to production behavior.

    Production: Live automation. No testing here — only monitoring and incident response. If you need to test in production, you failed at staging.

    Use separate API accounts for each environment. Development uses sandbox/test mode. Staging uses limited-production accounts. Production uses full-production accounts. This prevents test data from contaminating live systems.

    For API rate limits, each environment gets its own quota. A workflow that exhausts the development API limit doesn’t affect production. This isolation is why credential separation matters.

    Connecting to Your Infrastructure

    If you’re running n8n in Docker, the n8n Docker Deployment guide covers container configuration. Each environment runs as a separate container with its own volume mounts and environment variables.

    The n8n Docker Compose production stack defines multiple services. Extend it with additional compose files for development and staging environments. Share the base configuration and override environment-specific values.

    Understanding n8n’s execution engine helps you size each environment correctly. Production needs more CPU and memory for concurrent workflow execution. Development can run on minimal resources.

    Action Card: Environment Quick Setup

    Spin up a new staging environment in 5 minutes:

    `bash

    1. Create database

    createdb -U postgres n8n_staging

    2. Generate encryption key

    openssl rand -hex 32 > ./staging-encryption-key

    3. Export from development

    n8n export –all –output=./staging-wf-export.json

    4. Update URLs

    sed -i ‘s|dev|staging|g’ ./staging-wf-export.json

    5. Import to staging

    n8n import –all –input=./staging-wf-export.json

    6. Register webhooks with external services

    (manual step — update Slack, GitHub, etc.)

    `

    Document each environment setup in a README. Future-you will thank present-you when you need to recreate an environment after a server failure.

    References

  • n8n Docker Deployment
  • n8n Docker Compose Stack
  • n8n Execution Engine
  • PostgreSQL User Management
  • Leave a Reply

    Your email address will not be published. Required fields are marked *