Persistent Storage Requirements

Describe the problem/error/question

I’m deploying the n8n app via kubernetes and am unsure whether persistent storage is required.

We have a 1 instance of the 8n main app deployed connected to an external postgres db.

From the docs and ( Do I need persistent storage? ), I read that there is no need for persistent storage if we use an external database. Can this be confirmed?

Let’s say I start scaling and add workers. Do they need persistent storage? The required settings (enc key, etc) are set via environment variables.

If they do require persistent storage, does it have to be shared amongst the main and workers or can they have their own storage?

Just trying to wrap my head around this part before fully deploying and onboarding users.

Information on your n8n setup

  • n8n version: Version 1.122.4
  • Database (default: SQLite): GCP Postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main): one main instance for now
  • Running n8n via (Docker, npm, n8n cloud, desktop app): kubernetes
  • Operating system:

Hi @Ron_Ballesteros,

I would highly recommend always using persistent storage of your n8n data folder. This is especially important to share between your main and worker containers when using queue mode. In version n8n version 2 you there is a new requirement to also setup the task runners for code blocks and I believe this also uses the shared data dir (I might be wrong).

Here is an example docker compose using version 2 on queue mode

services:
  n8n-db:
    image: postgres:16.1
    restart: always
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_PASSWORD=n8n
      - POSTGRES_USER=n8n
    volumes:
      - postgres-data:/var/lib/postgresql/data

  n8n-redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redis-data:/data

  n8n-main:
    image: n8nio/n8n
    restart: always
    depends_on:
      - n8n-db
      - n8n-redis
    volumes:
      - n8n-data:/home/node/.n8n
    ports:
      - 4567:5678
      - 5680:5680
    environment:
      - WEBHOOK_URL=http://localhost:4567
      - NODE_ENV=production
      - N8N_HOST=localhost
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - N8N_SECURE_COOKIE=true
      - EXECUTIONS_MODE=queue
      # Task runner configuration for v2 (external mode)
      - N8N_RUNNERS_ENABLED=true
      - N8N_RUNNERS_MODE=external
      - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
      - N8N_RUNNERS_AUTH_TOKEN=your-secure-auth-token-change-this
      # Security settings
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false
      - N8N_BLOCK_ENV_ACCESS_IN_NODE=true
      - N8N_SKIP_AUTH_ON_OAUTH_CALLBACK=false
      # File access restriction
      - N8N_RESTRICT_FILE_ACCESS_TO=/home/node/.n8n-files
      # Binary data configuration (filesystem mode for regular mode)
      - N8N_DEFAULT_BINARY_DATA_MODE=filesystem
      - NODE_FUNCTION_ALLOW_BUILTIN=crypto
      - OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_HOST=n8n-db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_SCHEMA=n8n
      - DB_POSTGRESDB_PASSWORD=n8n
      - DB_POSTGRESDB_POOL_SIZE=40
      - DB_POSTGRESDB_CONNECTION_TIMEOUT=30000
      # Queue mode configuration
      - QUEUE_BULL_REDIS_HOST=n8n-redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_DB=0
      #  - N8N_LOG_LEVEL=debug
      - NODES_EXCLUDE="[n8n-nodes-base.localFileTrigger]"

  n8n-worker:
    image: n8nio/n8n
    restart: always
    command: worker --concurrency=6
    depends_on:
      - n8n-db
      - n8n-redis
      - n8n-worker-task-runner
    volumes:
      - n8n-data:/home/node/.n8n
    environment:
      - EXECUTIONS_MODE=queue
      - WEBHOOK_URL=http://localhost:4567
      - N8N_HOST=localhost
      - N8N_SKIP_DB_INIT=true
      # Task runner configuration for v2 (external mode)
      - N8N_RUNNERS_ENABLED=true
      - N8N_RUNNERS_MODE=external
      - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
      - N8N_RUNNERS_AUTH_TOKEN=your-secure-auth-token-change-this
      - N8N_PROCESS=worker
      # Security settings
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false
      - N8N_BLOCK_ENV_ACCESS_IN_NODE=true
      # File access restriction
      - N8N_RESTRICT_FILE_ACCESS_TO=/home/node/.n8n-files
      - NODE_FUNCTION_ALLOW_BUILTIN=crypto
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_HOST=n8n-db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_SCHEMA=n8n
      - DB_POSTGRESDB_PASSWORD=n8n
      - DB_POSTGRESDB_POOL_SIZE=40
      - DB_POSTGRESDB_CONNECTION_TIMEOUT=30000
      # Queue mode configuration
      - QUEUE_BULL_REDIS_HOST=n8n-redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_DB=0
      # - N8N_LOG_LEVEL=debug
      - NODES_EXCLUDE="[n8n-nodes-base.localFileTrigger]"

  # Task runner for n8n-worker with Python support for v2
  n8n-worker-task-runner:
    image: n8nio/runners
    restart: always
    depends_on:
      - n8n-db
      - n8n-redis
    environment:
      # Task runner configuration
      - N8N_RUNNERS_MODE=external
      - N8N_RUNNERS_TASK_BROKER_URI=http://n8n-worker:5679
      - N8N_RUNNERS_AUTH_TOKEN=your-secure-auth-token-change-this
      # Enable Python and JavaScript support
      - N8N_RUNNERS_ENABLED_TASK_TYPES=javascript,python
      # Auto shutdown after 15 seconds of inactivity
      - N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT=15
    volumes:
      # Shared volume for file access if needed
      - n8n-data:/home/node/.n8n

volumes:
  postgres-data:
  redis-data:
  n8n-data:

Fact checking myself now, it doesnt look like the workers need to have the data folder shared from the main instance. I’ll have to update my config and test it out

Hi @Wouter_Nigrini - thanks for the insight! So from your last statement the workers don’t need to share the external storage as the main instance?

I see support for aws s3 buckets, but being I’m on GCP, I wonder if gcs buckets would be supported. This would make it a lot easier for a lot of k8s deployments IMO.

I checked now. As a bare minimum you dont seem to need it. HOWEVER, if you’re planning on installing community nodes, you’ll need to share the data directory between main and worker. I cant confirm this at the moment.

Thanks for the input. I think I was able to make this work in a GKE cluster…

  • GCP postgres
  • GCP external memory store
  • GCS Bucket (shared with main instance and workers)
  • main instance (deployment resource with persistent storage)
  • workers (deployments with gcs bucket storage)

Everything seems to be working ok…

That is great news!