n8n plante avec « JavaScript heap out of memory » : causes et solutions
Publié le 4 août 2026 · 8 min de lecture
Un workflow qui tournait bien s'arrête net, l'interface n8n devient injoignable, et les logs affichent FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory. Ou pire : rien du tout — le conteneur redémarre en silence, l'exécution reste figée en « running » pour l'éternité, et seul un docker inspect révèle un OOMKilled: true. Dans les deux cas, le diagnostic est le même : l'exécution portait plus de données que la mémoire disponible ne pouvait en contenir.
Ce guide explique pourquoi n8n est particulièrement exposé à ce problème, comment identifier le node et le volume de données en cause, et déroule les cinq solutions dans l'ordre d'efficacité — en commençant par celles qui traitent la cause, pas seulement le symptôme.
Reconnaître le symptôme
L'erreur se présente sous plusieurs formes, selon que c'est Node.js ou le noyau Linux qui craque en premier :
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb85bc0 node::Abort() [node]
2: 0xa94834 node::FatalError(char const*, char const*) [node]
...
C'est le cas « propre » : Node.js atteint le plafond de sa propre heap et s'arrête en le disant. L'autre cas est plus sournois :
docker ps -a
# STATUS: Exited (137) 2 minutes ago
docker inspect --format '{{.State.OOMKilled}}' n8n
# true
L'exit code 137 (128 + signal 9) signifie que le noyau a tué le processus : le conteneur a dépassé sa limite mémoire et le OOM killer l'a abattu sans sommation — aucun message dans les logs n8n, juste un redémarrage si vous avez restart: always. Troisième visage, le plus trompeur : une exécution bloquée en « running » dans l'interface. Le processus est mort en plein traitement, n8n n'a jamais pu enregistrer la fin de l'exécution, et le statut ne sera jamais mis à jour.
Dans tous les cas, le déclencheur est le même : trop de données dans une seule exécution.
Pourquoi n8n sature sa mémoire
Il faut comprendre une propriété centrale de n8n : toutes les données d'une exécution vivent en mémoire, d'un bout à l'autre du workflow. Chaque node reçoit les items du précédent, produit les siens, et l'ensemble — y compris les résultats intermédiaires des nodes déjà passés — reste dans la heap jusqu'à la fin de l'exécution, notamment pour alimenter la sauvegarde de l'exécution et l'affichage pas à pas.
Les scénarios qui font déborder ce modèle sont toujours les mêmes :
- Des milliers d'items d'un coup : un
SELECTsansLIMIT, une API appelée sans pagination, un export complet de CRM. 50 000 items de quelques Ko chacun, multipliés par le nombre de nodes traversés, et la heap déborde. - Les binary data en mémoire : par défaut, les fichiers (PDF, images, Excel) transitent en base64 dans les données d'exécution — un encodage qui gonfle leur taille d'environ un tiers. Dix fichiers de 50 Mo suffisent à mettre l'instance à genoux.
- Les boucles qui accumulent : une boucle Loop Over Items garde en mémoire les résultats de toutes les itérations précédentes, puisqu'elles appartiennent à la même exécution. La boucle ne libère rien.
- Les gros fichiers à parser : un Excel de 80 Mo devient, une fois parsé en JSON, plusieurs centaines de Mo d'objets JavaScript.
- Les réponses API géantes : un endpoint qui renvoie 30 Mo de JSON, aussitôt dupliqués à chaque node de transformation.
Ce mécanisme n'a rien de spécifique à n8n. Une étude empirique de Lijie Xu, Wensheng Dou et leurs collègues, présentée à l'IEEE ISSRE 2015 (« A Characteristic Study on Out-of-Memory Errors in Distributed Data-Parallel Applications » — voir sur Google Scholar), a analysé des centaines d'erreurs out-of-memory réelles dans des applications de traitement de données : la cause dominante n'est pas un manque de RAM de la machine, mais des traitements qui matérialisent trop de données en mémoire d'un coup — gros résultats intermédiaires, données accumulées au fil du traitement. C'est mot pour mot ce qui se passe dans un workflow n8n qui charge 50 000 items : ajouter de la RAM repousse le mur, réduire ce qui est matérialisé le fait disparaître. D'où l'ordre des solutions qui suit.
Solution 1 — réduire la donnée en amont
La solution la plus efficace est aussi la moins spectaculaire : faire entrer moins de données dans l'exécution.
- Paginez à la source :
LIMIT/OFFSETen SQL, paramètrespage/per_paged'une API, option de pagination du node HTTP Request. Traitez 500 items par exécution plutôt que 50 000 en une. - Filtrez côté serveur : une clause
WHERE, un paramètreupdated_since— chaque item qui n'entre pas dans n8n est un item qui ne pèse rien. - Projetez : ne rapatriez que les champs utiles. Un
SELECT id, email, statuspèse dix fois moins qu'unSELECT *traînant des colonnes de texte libre. Côté API, cherchez un paramètrefields; côté n8n, un node Set en « Keep Only Set » juste après la source élimine le lest avant qu'il ne traverse tout le workflow.
Ces réflexes sont détaillés dans notre guide sur l'optimisation des performances des workflows n8n : dans la majorité des cas, ils suffisent à eux seuls à faire disparaître l'erreur.
Solution 2 — sortir les fichiers de la heap avec le mode filesystem
Si votre workflow manipule des fichiers, une seule variable d'environnement change la donne :
services:
n8n:
image: docker.n8n.io/n8nio/n8n
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem
volumes:
- n8n_data:/home/node/.n8n
En mode filesystem, les binary data sont écrits sur disque et seule une référence circule dans les données d'exécution — au lieu du contenu complet encodé en base64 dans la heap. Le volume persistant est indispensable, puisque c'est là que les fichiers atterrissent. Pour tout ce qui touche au dimensionnement, au nettoyage de ces fichiers et aux limites du mode mémoire, voyez notre guide sur la gestion des fichiers volumineux dans n8n.
Solution 3 — découper en lots et sub-workflows
Le point clé, souvent mal compris : une boucle Loop Over Items ne libère pas la mémoire entre les itérations, car tout appartient à la même exécution. Pour vraiment relâcher la pression, il faut déléguer chaque lot à un sub-workflow via le node Execute Sub-workflow : l'exécution enfant traite son lot, se termine, et sa mémoire est libérée — le workflow parent ne conserve que le petit résultat renvoyé.
Le motif type : un workflow parent qui pagine (solution 1) ou découpe en lots de 200 avec Loop Over Items, et qui appelle pour chaque lot un sub-workflow contenant toute la logique lourde (enrichissement, parsing, écriture). Pensez à limiter ce que l'enfant renvoie au parent — un simple compteur ou statut, pas les items traités. La mise en place complète (passage de données, mode d'exécution, gestion d'erreurs) est couverte dans notre guide des sub-workflows n8n.
Solution 4 — augmenter la heap Node… en cohérence avec le conteneur
Une fois la donnée réduite, si votre charge légitime dépasse encore le plafond par défaut de Node.js (de l'ordre de 2 Go selon la version et la mémoire détectée), relevez-le explicitement :
services:
n8n:
image: docker.n8n.io/n8nio/n8n
environment:
- NODE_OPTIONS=--max-old-space-size=4096
mem_limit: 5g
--max-old-space-size=4096 autorise environ 4 Go de heap V8. Le piège classique : fixer une heap de 4 Go dans un conteneur limité à 2 Go. Node croit disposer de 4 Go, ne déclenche pas son garbage collector agressivement, dépasse les 2 Go réels… et le noyau tue le conteneur — retour à l'exit code 137, sans message d'erreur, alors que vous pensiez avoir « augmenté la mémoire ». La règle : la heap à environ 75-80 % de la limite du conteneur, le reste couvrant les buffers, le code natif et la mémoire hors heap de Node. Et gardez en tête la leçon de l'étude citée plus haut : si le workflow matérialise dix fois trop de données, 4 Go déborderont comme 2 Go — cette solution accompagne les trois premières, elle ne les remplace pas.
Solution 5 — purger les exécutions et passer en mode queue
Deux mesures d'hygiène complètent le tableau pour les instances chargées. D'abord, la purge automatique des exécutions passées, qui allège la base et les données que n8n manipule :
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168 # en heures : 7 jours
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none # ne pas stocker le détail des succès
Le fonctionnement complet de cette purge (et le cas SQLite, qui réclame une étape de plus) est détaillé dans notre guide pour nettoyer les exécutions n8n.
Ensuite, si votre instance encaisse des charges lourdes ou simultanées, le mode queue répartit les exécutions sur des workers dédiés (EXECUTIONS_MODE=queue, Redis, un ou plusieurs conteneurs worker) : un workflow gourmand peut tuer un worker sans emporter l'interface ni les webhooks, et vous dimensionnez la mémoire par worker. C'est l'objet de notre guide du mode queue avec Redis.
Diagnostiquer : quel node, quelle taille ?
Avant de corriger, localisez le coupable :
- Repérez le dernier node exécuté : ouvrez l'exécution figée en « running » — le dernier node marqué terminé désigne le suivant comme suspect probable.
- Mesurez le payload : exécutez le workflow sur un petit échantillon (ajoutez un
LIMIT 10), ouvrez la sortie du node suspect et extrapolez — 10 items pour 40 Ko, donc 50 000 items pour ~200 Mo, avant multiplication par les nodes suivants. - Surveillez la consommation en direct :
docker stats n8npendant l'exécution montre la montée en mémoire et la marge restante avant la limite. - Confirmez l'OOM kill :
docker inspect --format '{{.State.OOMKilled}}' n8naprès un redémarrage inexpliqué lève le doute entre crash applicatif et exécution du conteneur.
Récapitulatif des variables d'environnement
| Variable | Rôle |
|---|---|
NODE_OPTIONS=--max-old-space-size=4096 |
Plafond de la heap V8 en Mo (à garder sous la limite du conteneur) |
N8N_DEFAULT_BINARY_DATA_MODE=filesystem |
Stocke les fichiers sur disque au lieu de la heap |
EXECUTIONS_DATA_PRUNE=true |
Active la purge automatique des exécutions |
EXECUTIONS_DATA_MAX_AGE=168 |
Âge maximal des exécutions conservées, en heures |
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none |
Ne stocke pas le détail des exécutions réussies |
EXECUTIONS_MODE=queue |
Mode queue : exécutions déportées sur des workers |
Côté docker-compose, ajoutez mem_limit (ou deploy.resources.limits.memory sous Swarm/Kubernetes) en cohérence avec la heap.
En résumé
« JavaScript heap out of memory » et OOMKilled sont deux visages du même problème : une exécution qui matérialise plus de données que la mémoire n'en contient. Traitez la cause avant le symptôme : paginez, filtrez et projetez en amont ; sortez les fichiers de la heap avec N8N_DEFAULT_BINARY_DATA_MODE=filesystem ; découpez les gros volumes en lots confiés à des sub-workflows, dont la mémoire se libère à chaque exécution enfant. Relevez ensuite seulement la heap avec NODE_OPTIONS=--max-old-space-size, toujours sous la limite mémoire du conteneur — un plafond Node supérieur à mem_limit garantit l'OOM kill silencieux. Et pour les instances de production chargées, purge des exécutions et mode queue avec workers transforment un point de défaillance unique en architecture qui encaisse.
FAQ
Questions fréquentes
Que signifie l'erreur « JavaScript heap out of memory » dans n8n ?
Node.js, le moteur qui exécute n8n, a atteint le plafond de sa heap : l'exécution en cours portait plus de données que la mémoire allouée ne pouvait en contenir. Ce n'est presque jamais un bug de n8n mais un workflow qui matérialise trop d'items d'un coup — gros export, binaires en base64, boucle qui accumule. Réduisez d'abord la donnée par exécution (pagination, filtres, lots en sub-workflows), passez les binaires en mode filesystem, et seulement ensuite relevez le plafond avec NODE_OPTIONS=--max-old-space-size.
Pourquoi mon conteneur n8n est-il OOMKilled (exit code 137) sans message d'erreur ?
L'exit code 137 signifie que le noyau Linux a tué le conteneur pour dépassement de sa limite mémoire — avant même que Node.js atteigne son propre plafond de heap, d'où l'absence du message FATAL ERROR dans les logs. Vérifiez avec docker inspect --format '{{.State.OOMKilled}}' n8n. La parade : aligner la limite du conteneur (mem_limit) et la heap Node, en gardant --max-old-space-size autour de 75-80 % de la limite du conteneur.
À quoi sert NODE_OPTIONS=--max-old-space-size dans n8n ?
Cette option fixe en mégaoctets le plafond de la heap V8 de Node.js : NODE_OPTIONS=--max-old-space-size=4096 autorise environ 4 Go. Elle doit rester inférieure à la limite mémoire du conteneur, sinon le noyau tuera le processus (OOMKilled) avant que Node ne gère proprement sa mémoire. Et elle ne corrige pas la cause : si le workflow charge dix fois trop de données, il finira par saturer 4 Go comme il saturait 2 Go.
Comment traiter des milliers d'items dans n8n sans saturer la mémoire ?
Paginez à la source et ne rapatriez que les champs utiles, puis découpez le traitement : Loop Over Items pour former des lots, et un sub-workflow (Execute Sub-workflow) qui traite chaque lot — l'exécution enfant libère sa mémoire en se terminant, ce qu'une simple boucle dans le même workflow ne fait pas. Passez les fichiers en N8N_DEFAULT_BINARY_DATA_MODE=filesystem, et pour les charges récurrentes lourdes, adoptez le mode queue avec des workers dédiés.
Bundle FlowKit Complet
269 €