Por qué n8n falla por memoria, y no por la razón que crees
V8, el motor JavaScript integrado en Node.js, tiene un límite de heap independiente de la RAM física. Por defecto oscila entre 512 MB y 1,5 GB según la versión de Node y la plataforma — en un VPS de 4 GB u 8 GB, la máquina no se queda sin memoria, pero el proceso V8 sí. Añadir más RAM al servidor no cambia nada sin NODE_OPTIONS=--max-old-space-size.
Segunda causa frecuente: en modo main (el predeterminado), n8n ejecuta los workflows en el mismo proceso que sirve los webhooks y la API. Un workflow pesado en datos — transformación CSV, agregación de miles de filas, llamadas GPT en bucle — monopoliza el heap durante su ejecución. Si varios se acumulan, se alcanza el límite V8 y el proceso se mata.
Tercera causa, más sutil: los jobs se acumulan en memoria cuando el modo queue está activado sin workers dedicados. La queue (Redis o BullMQ) descarga las ejecuciones del proceso principal, pero si ningún worker consume realmente los jobs, se acumulan, los callbacks permanecen en espera y el heap crece.
Señales que confirman un crash OOM en n8n
- Mensaje de salida exacto:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryen los logs del contenedor (docker logs n8n) - Crash silencioso bajo systemd: el servicio se reinicia automáticamente sin dejar rastro si
Restart=alwaysestá activo — comprobar conjournalctl -u n8n --since "1 hour ago" - OOM kill del kernel:
dmesg | grep -i oommuestraKilled process <pid> (node)antes del reinicio, independientemente de Node - Correlación con un workflow pesado: el crash ocurre siempre durante ejecuciones de tipo «procesamiento de archivo» o «bucle sobre miles de elementos»
- Heap estable durante horas y luego pico repentino: un workflow lanzado periódicamente acumula closures no liberadas — el heap sube en cada ejecución y no baja completamente
- Carga de memoria normal en htop: la RAM del sistema no está saturada en el momento del crash, lo que confirma que el problema es V8, no la máquina
Requisitos previos antes de intervenir
Estos pasos asumen que n8n ya está corriendo en tu VPS mediante Docker Compose. Si no es así, el artículo installer-n8n-vps cubre el despliegue completo desde cero — vuelve aquí una vez la instancia esté en marcha.
Lo que necesitas para aplicar las correcciones:
- Acceso SSH root al VPS y fichero docker-compose.yml editable
- Memoria disponible: un límite V8 de 4096 MB (--max-old-space-size=4096) requiere al menos 6 GB de RAM en el VPS para dejar margen al sistema operativo, workers y Redis
- Redis ya desplegado si cambias al modo queue — redis:7-alpine es suficiente para uso en un solo VPS
- Versión n8n 1.0 o superior: la separación main/worker está disponible desde la versión 0.214 pero solo es estable en producción a partir de 1.0
- Copia de seguridad de la base de datos antes de cualquier modificación del Compose — las tablas de credentials y ejecuciones no forman parte de la imagen Docker
Corregir el OOM: del diagnóstico a la configuración estable
Confirmar la causa en los logs
Lee las últimas 200 líneas del contenedor en el momento del crash:
docker logs n8n --tail 200 2>&1 | grep -E "FATAL|heap|OOM|Killed"Si ves
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, es un crash V8. Si vesKilledsolo sin mensaje Node, es el OOM killer del kernel — ambos pueden coexistir en el mismo incidente.Establecer el límite V8 mediante NODE_OPTIONS
En tu
docker-compose.yml, añade la variable de entornoNODE_OPTIONSal servicio n8n. Valor recomendado según la RAM del VPS:- VPS 4 GB:
--max-old-space-size=2048
- VPS 8 GB:--max-old-space-size=4096
- VPS 16 GB:--max-old-space-size=8192Regla: reserva aproximadamente la mitad de la RAM disponible tras el sistema operativo y servicios auxiliares (Redis, proxy). No superar el 70% de la RAM total.
services: n8n: image: n8nio/n8n:latest environment: - NODE_OPTIONS=--max-old-space-size=4096 # ... otras variablesVerificar que el valor se lee correctamente
Tras
docker compose up -d, verifica que Node lee el límite:docker exec n8n node -e "const v8=require('v8'); console.log(v8.getHeapStatistics().heap_size_limit / 1024 / 1024, 'MB')"El valor mostrado debe aproximarse a tu
--max-old-space-size. Si sigue mostrando 512 o 1500, la variable de entorno no se está pasando al proceso — verifica queNODE_OPTIONSestá en la secciónenvironment:del servicio.Cambiar al modo queue con Redis
El modo
main(predeterminado) ejecuta todo en un único proceso. Para instancias que gestionan más de 20 workflows simultáneos o payloads voluminosos, separa los roles:services: redis: image: redis:7-alpine restart: unless-stopped volumes: - redis_data:/data n8n: image: n8nio/n8n:latest environment: - NODE_OPTIONS=--max-old-space-size=2048 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 depends_on: - redis ports: - "5678:5678" n8n-worker: image: n8nio/n8n:latest command: worker environment: - NODE_OPTIONS=--max-old-space-size=4096 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 depends_on: - redis scale: 2 volumes: redis_data:El servicio
n8nse convierte en el proceso principal (API + UI + webhooks) con un límite moderado. El servicion8n-workergestiona las ejecuciones con un límite mayor. La directivascale: 2lanza dos workers — ajusta según tus necesidades.Separar el proceso webhook si el tráfico lo requiere
En instancias que reciben muchos webhooks en paralelo, el proceso principal puede saturarse incluso sin ejecutar workflows. n8n ofrece un modo webhook dedicado:
n8n-webhook: image: n8nio/n8n:latest command: webhook environment: - NODE_OPTIONS=--max-old-space-size=1024 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 - N8N_DISABLE_UI=true depends_on: - redis ports: - "5679:5678"Configura tu reverse proxy para enrutar
/webhook/al puerto 5679 y el resto al puerto 5678 del proceso principal. El modo webhook está disponible desde n8n 1.0.Activar el garbage collector explícito para workflows pesados
Para workflows que procesan archivos grandes o bucles largos, puedes ayudar a V8 a liberar memoria de forma más agresiva:
NODE_OPTIONS="--max-old-space-size=4096 --expose-gc"Esto expone
global.gc()— n8n puede llamarlo entre los pasos de un workflow. Combínalo conEXECUTIONS_DATA_SAVE_ON_SUCCESS=nonesi no necesitas el historial de ejecución: los datos de ejecución retenidos suelen representar el 30-50% del heap.Monitorizar el heap tras la corrección
Activa las métricas de n8n para observar la evolución del heap sin intervención manual:
N8N_METRICS=true N8N_METRICS_PREFIX=n8n_El endpoint
/metrics(puerto 5678) exponenodejs_heap_size_used_bytesynodejs_heap_size_total_bytes, compatibles con Prometheus. Un dashboard básico de Grafana sobre estas dos métricas te alertará mucho antes del próximo crash.
Limitar el tamaño del payload de ejecución
El parámetro EXECUTIONS_DATA_MAX_SIZE (en bytes, sin límite por defecto) corta una ejecución antes de que pueda desbordar el heap. Valor recomendado para instancias de propósito general: 16777216 (16 MB). Un workflow que supere este umbral falla de forma limpia en lugar de matar todo el proceso. Combínalo con EXECUTIONS_DATA_PRUNE=true y EXECUTIONS_DATA_MAX_AGE=168 (una semana) para evitar la acumulación de datos de ejecuciones pasadas.
Configuración post-corrección: variables de entorno útiles
Una vez resuelto el OOM, estas variables consolidan la estabilidad de la instancia:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem — almacena los archivos binarios en disco en lugar de en memoria; indispensable para workflows que manipulan archivos CSV o PDF voluminosos
- OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true — las ejecuciones manuales (lanzadas desde el editor) también pasan por los workers, evitando presión sobre el heap del proceso principal durante las pruebas
- N8N_RUNNERS_ENABLED=true y N8N_RUNNERS_MAX_CONCURRENCY=5 — activa el task runner experimental (n8n 1.10+) que aísla cada ejecución en un subproceso, impidiendo que un único workflow consuma todo el heap disponible
- DB_POSTGRESDB_* — migrar de SQLite a PostgreSQL en instancias de alto volumen: SQLite serializa todas las lecturas/escrituras y puede bloquear a los workers, amplificando la presión de memoria
Resolución de problemas — errores reales y sus causas
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Causa directa: el heap V8 ha alcanzado su límite. Solución: añadir NODE_OPTIONS=--max-old-space-size=<n> en las variables de entorno del contenedor, con un valor calibrado según la RAM disponible (ver paso 2).
Killed en los logs, sin mensaje Node
Causa: el OOM killer del kernel Linux ha terminado el proceso antes de que V8 pudiera emitir su mensaje. Ocurre cuando la memoria física está realmente agotada — distinto de un crash V8 puro. Verificar con dmesg | grep -i oom. Reducir --max-old-space-size o añadir RAM, y activar EXECUTIONS_DATA_SAVE_ON_SUCCESS=none.
Los workers no consumen jobs pese a EXECUTIONS_MODE=queue
Causa frecuente: DB_TYPE y las variables de base de datos no se pasan a los workers. Cada servicio del Compose debe tener sus propias variables de conexión. Verificar con docker exec n8n-worker env | grep DB_.
El heap sube tras cada ejecución y no baja
Causa: un closure retiene una referencia a un array grande entre ejecuciones. Activar --expose-gc en NODE_OPTIONS y añadir EXECUTIONS_DATA_SAVE_ON_SUCCESS=none. Si persiste, cambiar al modo task runner (N8N_RUNNERS_ENABLED=true).
Error: Redis connection failed tras cambiar al modo queue
Causa: QUEUE_BULL_REDIS_HOST apunta a localhost en lugar del nombre de servicio Docker. En una red Compose, el proceso principal y los workers alcanzan Redis por su nombre de servicio (redis en el ejemplo), no 127.0.0.1.
Recursos y próximos pasos
La documentación oficial de n8n sobre errores de memoria (docs.n8n.io/hosting/scaling/memory-errors) detalla los valores recomendados de --max-old-space-size según la RAM disponible y lista los parámetros de escalado. El issue de GitHub n8n-io/n8n#17461 (OOM en producción, abierto en marzo de 2026, 80+ comentarios) documenta casos reales — incluyendo la correlación entre workflows de procesamiento CSV y crash heap — y configuraciones que han estabilizado instancias similares a la tuya.
Si gestionas varias instancias de n8n para distintos clientes, la separación main/worker descrita aquí es también la base de una arquitectura multi-tenant: cada cliente puede tener su propio pool de workers con un límite V8 independiente, sin que un workflow pesado de una cuenta afecte a las demás.