N8n Gradually Consumes All Server RAM

n8n gradually eats uPreformatted textp all the server RAM

Workflow did not finish, possible out-of-memory issue

I used to run n8n with SQLite a couple of years ago on a server with 2GB of RAM, and it worked fine without any issues. My workflows have remained the same since then.

Later, I decided to switch to n8n with PostgreSQL to avoid memory bottlenecks. I did a clean installation using Docker, but now I’m facing problems. I upgraded to a server with 4GB of RAM, but it’s still not enough. Over time, n8n consumes all the server’s memory, leading to an error: “Workflow did not finish, possible out-of-memory issue.” After this, the server’s memory clears, and the cycle repeats.

What could be causing this issue?

the docker compost file is like this:

version: '3.9'

services:
  postgres:
    container_name: postgres
    image: postgres:16
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    networks:
      - portainer_default

  n8n:
    container_name: n8n
    image: docker.n8n.io/n8nio/n8n
    restart: always
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - NODE_OPTIONS=--max-old-space-size=2048
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=websecure
      - traefik.http.services.n8n.loadbalancer.server.port=5678
      - traefik.http.routers.n8n.tls.certresolver=leresolver
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
      - traefik.http.routers.n8n.middlewares=n8n@docker
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files
    networks:
      - portainer_default
    ports:
      - "127.0.0.1:5678:5678"

volumes:
  postgres_data:
  n8n_data:

networks:
  portainer_default:
    external: true
    name: portainer_default

could it be because of the enabled setting - N8N_RUNNERS_ENABLED=true?

Information on your n8n setup

  • n8n version: 1.91.2
  • Database (default: SQLite): Postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main): own, main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker Compose
  • Operating system: Ubuntu 24.04
1 Like

If we study the atop logs, then apparently the node process consumes all the RAM of the server. How can I fix this?

1 Like

Hello,

It shouldn’t be because of runners being enabled, but it could be because binary data isn’t being released, and the default setting is in ram memory.

But you can try enable

N8N_DEFAULT_BINARY_DATA_MODE=filesystem

By default, n8n uses memory to store binary data. Enterprise users can choose to use an external service instead. Refer to External storage for more information on using external storage for binary data.

Also it would be worth setting execution vars to clear too.

EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=false
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=50000

How much data is being processes in workflow? I’m guessing quite alot.

Hope this helps,

Samuel

1 Like

I have set the parameter “N8N_DEFAULT_BINARY_DATA_MODE=file system” and will continue to monitor the behavior of n8n. Could there be another problem that I have n8n running inside portainer through the stack?

1 Like

@Danilov_Vovka it’s most likely the binary data, hope all goes well.

Samuel

I think your decision helped me, now there are no sudden RAM spikes. Now the consumption reaches 2GB. Do I need to leave the setting - NODE_OPTIONS=–max-old-space-size=2048, which I added earlier?

1 Like

@Danilov_Vovka depends on the instance size, you can probably remove tbh, btw if working much better now, I would highly appreciate marking this as the solution if okay, be much appreciated.

Many thanks,

Samuel

unfortunately, the RAM gets clogged anyway.

docker file:

version: '3.9'

services:
  postgres:
    container_name: postgres
    image: postgres:16
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    networks:
      - portainer_default

  n8n:
    container_name: n8n
    image: docker.n8n.io/n8nio/n8n
    restart: always
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - NODE_OPTIONS=--max-old-space-size=2048
      - N8N_DEFAULT_BINARY_DATA_MODE=filesystem
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=websecure
      - traefik.http.services.n8n.loadbalancer.server.port=5678
      - traefik.http.routers.n8n.tls.certresolver=leresolver
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
      - traefik.http.routers.n8n.middlewares=n8n@docker
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files
    networks:
      - portainer_default
    ports:
      - "127.0.0.1:5678:5678"

volumes:
  postgres_data:
  n8n_data:

networks:
  portainer_default:
    external: true
    name: portainer_default

PID 590773 (node): 1.9 GB is the largest consumer.
PID 831 (dockerd): 54.7 MB.
PID 2314 (traefik): 52.2 MB.
PID 2305 (portainer): 48.5 MB.
PID 590887 (node): 110.2 MB.

CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
55321cbc6f73 n8n 0.12% 2.017GiB / 3.824GiB 52.74% 1.18GB / 2.96GB 1.48MB / 90MB 20
785b27587867 postgres 0.00% 179.9MiB / 3.824GiB 4.59% 2.89GB / 293MB 1.45GB / 3.43GB 7
873d181fa495 portainer 0.00% 28.08MiB / 3.824GiB 0.72% 12.8MB / 90.7MB 111MB / 401MB 6
4f58718a9cdb traefik 0.00% 38.54MiB / 3.824GiB 0.98% 1.04GB / 1.03GB 160MB / 6.37MB 9

Hey @Danilov_Vovka

Could you try setup, N8n + Grafana Full Node.js Metrics Dashboard (JSON Example Included!)

I think it be good to watch further node stats, see if it’s just garbage cleanup or other area, let me know if you’d like some help.

What does the workflow do btw, is it processing much bin data or execution data?

Best regards,

Samuel

Is it a server with only one (v) cpu?

2 x 3.3 GHz CPU • 4 GB RAM • 50 GB NVMe
I used to have everything running on 1 x 3.3GHz CPU • 2 GB RAM and there were no problems. it all started after switching to a clean install + postgres.

@King_Samuel_David

I tried to deploy grafana, but I have something wrong. metrics are not counted, although N8N gives them away locally.

That’s my stack.:

version: '3.9'

networks:
  monitoring:
    driver: bridge
  portainer_default:
    external: true
    name: portainer_default

volumes:
  prometheus_data: {}
  grafana_data: {}

services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "127.0.0.1:9100:9100"
    networks:
      - monitoring

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    volumes:
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
    entrypoint:
      - /bin/sh
      - -c
      - |
        echo "global:
          scrape_interval: 15s
        scrape_configs:
          - job_name: 'n8n'
            static_configs:
              - targets: ['n8n:5678']
          - job_name: 'node-exporter'
            static_configs:
              - targets: ['node-exporter:9100']
        " > /etc/prometheus/prometheus.yml && /bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus --web.console.libraries=/etc/prometheus/console_libraries --web.console.templates=/etc/prometheus/consoles --web.enable-lifecycle
    ports:
      - "127.0.0.1:9090:9090"
    networks:
      - monitoring
      - portainer_default

  grafana:
    image: grafana/grafana-enterprise:latest
    container_name: grafana
    restart: unless-stopped
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - "MY-IP-ADRESS-SERVER:3000:3000"
    networks:
      - monitoring
      - portainer_default

The target is active and data collection seems to be working.


then why don’t the charts in the dashboard work?

@King_Samuel_David

I think I’ve managed to set up grafana. how many metrics do I need to collect and which ones?

1 Like

@Danilov_Vovka
Hello

I would be watching the GC as it may be the issue, if you notice anything, that matches the spikes and drops, then this should help identify the issue further.

Best regards,

Samuel

@King_Samuel_David

Hi.

Statistics have been collected for the last 24 hours since the n8n crashed due to lack of memory:





Will it be possible to identify a RAM leak?

In most cases docker containers will consume as much memory or cpu as is available. Off course you can enahnce workflows which might consume a lot of memory etc. One other way to limit the amount of memory a container can consume is by adding the mem_limit docker param. Below is an example where we limited a dev instance to not consume the hosts available ram:

  n8n-dev:
    image: docker.n8n.io/n8nio/n8n:1.64.3
    container_name: n8n-dev
    restart: always
    mem_limit: 1024m
    cpus: 1
    depends_on:
      - n8n-dev-db
    env_file:
      - .env

Hey @Danilov_Vovka

It looks like heapspace old, grows and grows, over this period, other things look consistant like event loop lag,


I think you can try change the value, it may help. I noticed you set at 2gb already.

NODE_OPTIONS=--max-old-space-size=<limit>

You can try disable Taskrunner, this will use more mem I believe or maybe adjust concurrency
N8N_CONCURRENCY_PRODUCTION_LIMIT=3

N8N_DEFAULT_BINARY_DATA_MODE I would try this first, enabling filesystem storage not memory,

Hopefully changing these will help, please do monitor further, am wondering if there are any other options, I dont think this is consider a RAM leak, as this is normal behaviour of heap spaces, In Node.js, the “old space” refers to the part of the V8 heap where long-lived objects are stored after surviving several garbage collection cycles.

Samuel

I have previously used the settings NODE_OPTIONS=–max-old-space-size=2000 and N8N_DEFAULT_BINARY_DATA_MODE=filesystem

I have now set the size to 1024 and added mem_limit: 1024m.

the current docker file looks like this:

version: '3.9'

services:
  postgres:
    container_name: postgres
    image: postgres:16
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    networks:
      - portainer_default

  n8n:
    container_name: n8n
    image: docker.n8n.io/n8nio/n8n
    restart: always
    mem_limit: 1024m
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_RUNNERS_ENABLED=true
      - NODE_OPTIONS=--max-old-space-size=1024
      - N8N_DEFAULT_BINARY_DATA_MODE=filesystem
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=1440
      - EXECUTIONS_DATA_PRUNE_MAX_COUNT=50000
      - N8N_METRICS=true
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=websecure
      - traefik.http.services.n8n.loadbalancer.server.port=5678
      - traefik.http.routers.n8n.tls.certresolver=leresolver
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
      - traefik.http.routers.n8n.middlewares=n8n@docker
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files
    networks:
      - portainer_default
    ports:
      - "127.0.0.1:5678:5678"

volumes:
  postgres_data:
  n8n_data:

networks:
  portainer_default:
    external: true
    name: portainer_default

I’ll keep watching

Made some edits above, thanks, you have filesystem enabled. and it 100 percent node process, hmm did you try disable runners?

Samuel

Mod - N8N_RUNNERS_ENABLED=true I haven’t tried disabling it yet. But I also think it’s because of him, because I didn’t use this mode last time.

I’ll check the stats in 24 hours.

1 Like