Pourquoi n8n crashe en mémoire, et pas pour la raison qu'on croit
V8, le moteur JavaScript embarqué dans Node.js, dispose d'un plafond de heap indépendant de la RAM physique. Par défaut il oscille entre 512 Mo et 1,5 Go selon la version de Node et la plateforme — sur un VPS à 4 Go ou 8 Go, la machine n'est pas à court de mémoire, mais le processus V8, lui, l'est. Allouer plus de RAM au serveur ne change rien sans NODE_OPTIONS=--max-old-space-size.
Deuxième cause fréquente : en mode main (le mode par défaut), n8n exécute les workflows dans le même processus qui sert les webhooks et l'API. Un workflow lourd en données — transformation CSV, agrégation de plusieurs milliers de lignes, appel GPT en boucle — monopolise le heap pendant son exécution. Si plusieurs s'accumulent, le plafond V8 est atteint et le processus est tué.
Troisième cause, plus subtile : les jobs s'accumulent en mémoire quand le mode queue est activé sans workers dédiés. La queue (Redis ou BullMQ) déleste le main process des exécutions, mais si aucun worker ne consomme réellement les jobs, ceux-ci s'accumulent, les callbacks restent en attente et le heap grossit.
Signaux qui confirment un crash OOM n8n
- Message de sortie exact :
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memorydans les logs du conteneur (docker logs n8n) - Crash silencieux sous systemd : le service redémarre automatiquement sans laisser de trace si
Restart=alwaysest actif — vérifierjournalctl -u n8n --since "1 hour ago" - OOM kill du noyau :
dmesg | grep -i oommontreKilled process <pid> (node)avant le redémarrage, indépendamment de Node - Corrélation avec un workflow lourd : le crash survient toujours pendant les exécutions de type « traitement de fichier » ou « boucle sur plusieurs milliers d'items »
- Heap stable pendant des heures puis pic soudain : un workflow déclenché périodiquement accumule des closures non libérées — le heap monte à chaque run et ne redescend pas complètement
- Charge mémoire normale sur htop : la RAM système n'est pas saturée au moment du crash, ce qui confirme que le problème est V8, pas la machine
Prérequis avant d'intervenir
Ces étapes supposent que n8n tourne déjà sur votre VPS via Docker Compose. Si ce n'est pas le cas, l'article installer-n8n-vps couvre le déploiement complet depuis zéro — revenez ici une fois l'instance en place.
Ce qu'il vous faut pour appliquer les corrections :
- Accès SSH root au VPS et fichier docker-compose.yml éditable
- Mémoire disponible : un plafond V8 de 4 096 Mo (--max-old-space-size=4096) suppose au moins 6 Go de RAM sur le VPS pour laisser de la marge au système d'exploitation, aux workers et à Redis
- Redis déjà déployé si vous passez en mode queue — redis:7-alpine suffit pour un usage mono-VPS
- Version n8n 1.0 ou supérieure : la séparation main/worker est disponible depuis la version 0.214 mais n'est stable en production qu'à partir de 1.0
- Sauvegarde de la base de données avant toute modification du Compose — les tables de credentials et d'exécutions ne font pas partie de l'image Docker
Corriger l'OOM : du diagnostic à la configuration stable
Confirmer la cause dans les logs
Lisez les 200 dernières lignes du conteneur au moment du crash :
docker logs n8n --tail 200 2>&1 | grep -E "FATAL|heap|OOM|Killed"Si vous voyez
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, c'est un crash V8. Si vous voyezKilledseul sans message Node, c'est l'OOM killer du noyau — les deux peuvent coexister sur le même incident.Poser le plafond V8 dans la variable NODE_OPTIONS
Dans votre
docker-compose.yml, ajoutez la variable d'environnementNODE_OPTIONSsur le service n8n. La valeur recommandée selon la RAM du VPS :- VPS 4 Go :
--max-old-space-size=2048
- VPS 8 Go :--max-old-space-size=4096
- VPS 16 Go :--max-old-space-size=8192Règle : réserver environ la moitié de la RAM disponible après système d'exploitation et services annexes (Redis, proxy). Ne pas dépasser 70 % de la RAM totale.
services: n8n: image: n8nio/n8n:latest environment: - NODE_OPTIONS=--max-old-space-size=4096 # ... autres variablesAttention : Ne mettez pas
NODE_OPTIONSà l'intérieur d'un span de backticks dans vos fichiers.envsi vous utilisez la substitution de variables — la valeur doit être une chaîne littérale.Vérifier que la valeur est bien prise en compte
Après
docker compose up -d, vérifiez que Node lit bien le plafond :docker exec n8n node -e "const v8=require('v8'); console.log(v8.getHeapStatistics().heap_size_limit / 1024 / 1024, 'MB')"La valeur affichée doit approcher votre
--max-old-space-size. Si elle affiche encore 512 ou 1500, la variable d'environnement n'est pas transmise au processus — vérifiez queNODE_OPTIONSest dans la sectionenvironment:du service, pas dansenv_file:avec une valeur mal parsée.Passer en mode queue avec Redis
Le mode
main(défaut) exécute tout dans un seul processus. Pour les instances qui traitent plus de 20 workflows simultanés ou des payloads volumineux, séparez les rôles :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:Le service
n8ndevient le main process (API + interface + webhooks) avec un plafond modéré. Le servicen8n-workerprend en charge les exécutions avec un plafond plus généreux. La directivescale: 2lance deux workers — ajustez selon vos besoins.Séparer le webhook process si le trafic l'exige
Sur les instances qui reçoivent beaucoup de webhooks en parallèle, le main process peut être saturé même sans exécuter de workflows. n8n propose un mode webhook dédié :
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"Configurez ensuite votre reverse proxy pour router
/webhook/vers le port 5679 et le reste vers le port 5678 du main process. Le mode webhook est disponible depuis n8n 1.0.Activer le garbage collector explicite pour les workflows lourds
Pour les workflows qui traitent des fichiers volumineux ou des boucles longues, vous pouvez aider V8 à libérer la mémoire plus agressivement :
NODE_OPTIONS="--max-old-space-size=4096 --expose-gc"Cette option expose
global.gc()— n8n peut l'appeler entre les étapes d'un workflow. À combiner avec le paramètreEXECUTIONS_DATA_SAVE_ON_SUCCESS=nonesi vous n'avez pas besoin de l'historique d'exécution : les données d'exécution conservées en mémoire représentent souvent 30 à 50 % du heap.Surveiller le heap après correction
Installez un endpoint de métriques n8n pour observer l'évolution du heap sans avoir à intervenir à la main :
N8N_METRICS=true N8N_METRICS_PREFIX=n8n_L'endpoint
/metrics(port 5678) expose alorsnodejs_heap_size_used_bytesetnodejs_heap_size_total_bytes, compatibles Prometheus. Un dashboard Grafana basique sur ces deux métriques vous alertera bien avant le prochain crash.
Limiter la taille des payloads d'exécution
Le paramètre EXECUTIONS_DATA_MAX_SIZE (en bytes, défaut : aucune limite) coupe une exécution avant qu'elle ne puisse faire déborder le heap. Valeur recommandée pour les instances généralistes : 16777216 (16 Mo). Un workflow qui dépasse ce seuil échoue proprement au lieu de tuer le processus entier. Combinez-le avec EXECUTIONS_DATA_PRUNE=true et EXECUTIONS_DATA_MAX_AGE=168 (une semaine) pour éviter l'accumulation des données d'exécution passées en base.
Configuration post-correction : variables d'environnement utiles
Une fois l'OOM résolu, ces variables consolidaent la stabilité de l'instance :
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem — stocke les fichiers binaires sur disque plutôt qu'en mémoire ; indispensable pour les workflows qui manipulent des fichiers CSV ou PDF volumineux
- OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true — les exécutions manuelles (déclenchées depuis l'éditeur) passent aussi par les workers, évitant de peser sur le heap du main process pendant les tests
- N8N_RUNNERS_ENABLED=true et N8N_RUNNERS_MAX_CONCURRENCY=5 — active le task runner expérimental (n8n 1.10+) qui isole chaque exécution dans un sous-processus, empêchant un seul workflow de consommer tout le heap disponible
- DB_POSTGRESDB_* — migrer de SQLite à PostgreSQL sur les instances à fort volume : SQLite sérialise toutes les lectures/écritures et peut bloquer les workers, amplifiant la pression mémoire
Dépannage — erreurs réelles et leurs causes
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Cause directe : le heap V8 a atteint son plafond. Solution : ajouter NODE_OPTIONS=--max-old-space-size=<n> dans les variables d'environnement du conteneur, avec une valeur calibrée sur la RAM disponible (voir étape 2).
Killed dans les logs, sans message Node
Cause : l'OOM killer du noyau Linux a terminé le processus avant que V8 ne puisse émettre son message. Survient quand la mémoire physique est effectivement épuisée — différent du crash V8 pur. Vérifier avec dmesg | grep -i oom. Réduire --max-old-space-size ou ajouter de la RAM, et activer EXECUTIONS_DATA_SAVE_ON_SUCCESS=none pour alléger l'empreinte.
Les workers ne consomment pas les jobs malgré EXECUTIONS_MODE=queue
Cause fréquente : DB_TYPE et les variables de base de données ne sont pas transmises aux workers. Chaque service du Compose doit avoir ses propres variables de connexion — le worker n'hérite pas de la configuration du main process. Vérifiez avec docker exec n8n-worker env | grep DB_.
Le heap grimpe après chaque run et ne redescend pas
Cause : une closure retient une référence à un grand tableau entre les exécutions. Activer --expose-gc dans NODE_OPTIONS et ajouter EXECUTIONS_DATA_SAVE_ON_SUCCESS=none pour éviter que les données d'exécution ne s'accumulent. Si le comportement persiste, passer en mode task runner (N8N_RUNNERS_ENABLED=true) qui isole chaque workflow.
Error: Redis connection failed après le passage en mode queue
Cause : QUEUE_BULL_REDIS_HOST pointe vers localhost au lieu du nom de service Docker. Dans un réseau Compose, le main process et les workers atteignent Redis par son nom de service (redis dans l'exemple ci-dessus), pas par 127.0.0.1.
Ressources et prochaines étapes
La documentation officielle n8n sur les erreurs mémoire (docs.n8n.io/hosting/scaling/memory-errors) détaille les valeurs recommandées de --max-old-space-size selon la RAM disponible et liste les paramètres de scaling. L'issue GitHub n8n-io/n8n#17461 (OOM en production, ouverte en mars 2026, 80+ commentaires) documente des cas réels — notamment la corrélation entre workflows de traitement CSV et crash heap — et les configurations qui ont stabilisé des instances similaires à la vôtre.
Si vous gérez plusieurs instances n8n pour des clients différents, la séparation main/worker décrite ici est aussi la base d'une architecture multi-tenant : chaque client peut avoir son propre pool de workers avec un plafond V8 indépendant, sans qu'un workflow lourd d'un compte n'impacte les autres.