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
BramKn
June 2, 2025, 8:32pm
10
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