FlowKit

Historique d'exécutions n8n qui gonfle : purge automatique et base de données qui reprend du poids

Publié le 3 août 2026 · 10 min de lecture

Le scénario est presque toujours le même : une instance n8n self-hosted qui tournait bien depuis des mois se met à ralentir, l'interface met plusieurs secondes à afficher la liste des exécutions, et un df -h sur le serveur révèle un volume Docker ou une base de données qui pèse plusieurs gigaoctets. La cause est structurelle, pas accidentelle : par défaut, chaque exécution de workflow stocke en base les données de tous les nodes traversés — les payloads complets, en entrée comme en sortie. Un workflow de dix nodes qui brasse des réponses d'API de quelques centaines de kilooctets écrit plusieurs mégaoctets par exécution ; un workflow IA ou RAG qui manipule des documents entiers, des embeddings et des réponses de LLM en écrit bien davantage. Multipliez par des centaines d'exécutions par jour, et la base gonfle mécaniquement.

n8n embarque pourtant une purge automatique, activée par défaut. Ce guide explique comment elle fonctionne réellement, comment la régler, pourquoi la suppression des exécutions ne rend pas toujours l'espace disque (le cas SQLite est le plus piégeux), et surtout comment réduire à la source ce qui entre en base — la seule stratégie qui tienne sur la durée.

Ce que n8n stocke à chaque exécution — et pourquoi ça pèse

Quand un workflow s'exécute, n8n enregistre l'exécution elle-même (statut, horodatage, workflow concerné) et, séparément, les données produites par chaque node : les items JSON complets tels que vous les voyez en cliquant sur un node d'une exécution passée. C'est cette seconde partie qui pèse. Rouvrir une exécution vieille de trois jours et inspecter la sortie exacte de chaque node est un confort de débogage précieux — mais facturé en gigaoctets.

Trois profils de workflows font grossir la base plus vite que les autres :

  • Les workflows IA et RAG : documents sources, chunks, embeddings, réponses complètes des modèles — chaque exécution peut transporter des mégaoctets de texte d'un node à l'autre, et tout est conservé.
  • Les workflows à haute fréquence : un polling toutes les minutes produit 1 440 exécutions par jour, même quand il ne trouve rien à traiter.
  • Les workflows qui manipulent des fichiers : si les données binaires restent en base (le mode par défaut), chaque PDF ou image traversant le workflow est stocké avec l'exécution — notre guide sur la gestion des fichiers volumineux et du binary data détaille ce mécanisme.

Ce phénomène n'a rien de propre à n8n. Une étude de référence d'Oliner, Ganapathi et Xu publiée en 2012 dans Communications of the ACM (« Advances and challenges in log analysis » — voir sur Google Scholar) faisait déjà ce constat sur les journaux systèmes en général : les logs croissent plus vite que la capacité à les exploiter, et la vraie question n'est pas de tout garder, mais de décider quoi conserver et pourquoi. C'est exactement le bon cadre pour penser l'historique d'exécutions n8n : un outil de diagnostic, pas une archive.

La purge automatique : EXECUTIONS_DATA_PRUNE et ses deux plafonds

n8n purge les vieilles exécutions automatiquement, sans configuration. Trois variables d'environnement pilotent ce mécanisme :

# Purge automatique (activée par défaut)
EXECUTIONS_DATA_PRUNE=true

# Âge maximal d'une exécution conservée, en heures
# 336 par défaut = 14 jours
EXECUTIONS_DATA_MAX_AGE=336

# Nombre maximal d'exécutions conservées
# 10000 par défaut
EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000

Les deux plafonds s'appliquent conjointement : une exécution est purgée dès qu'elle dépasse l'âge maximal ou que le total conservé excède le plafond de nombre. Sur une instance chargée, c'est souvent EXECUTIONS_DATA_PRUNE_MAX_COUNT qui mord en premier ; sur une instance calme, c'est l'âge. Pour une production classique de PME, resserrer les deux valeurs est le premier réflexe :

# Extrait docker-compose.yml
services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    environment:
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168        # 7 jours
      - EXECUTIONS_DATA_PRUNE_MAX_COUNT=5000

Un détail utile pour interpréter ce que vous observez : la purge procède en deux temps. Les exécutions concernées sont d'abord marquées comme supprimées (un « soft delete » — elles disparaissent de l'interface), puis réellement effacées de la base lors d'une passe ultérieure. Il est donc normal de ne pas voir la base réagir à la seconde où le seuil est franchi. Et comme nous allons le voir, même la suppression réelle ne rend pas nécessairement l'espace disque au système.

Ces variables se règlent comme toutes les autres — notre guide des variables d'environnement n8n couvre les différentes façons de les injecter selon votre installation.

Réduire à la source : ne stocker que ce qui sert

La purge limite le stock ; les variables de sauvegarde limitent le flux. C'est le levier le plus puissant, car il agit avant que les données n'entrent en base :

# Ne pas conserver les exécutions réussies
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none

# Conserver toutes les exécutions en échec
EXECUTIONS_DATA_SAVE_ON_ERROR=all

# Ne pas sauvegarder l'état intermédiaire pendant l'exécution
# (false par défaut — le laisser ainsi : chaque node écrirait en base)
EXECUTIONS_DATA_SAVE_ON_PROGRESS=false

# Conserver ou non les exécutions lancées manuellement depuis l'éditeur
EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true

La combinaison SAVE_ON_SUCCESS=none + SAVE_ON_ERROR=all est le réglage de production le plus courant : les exécutions qui se passent bien ne laissent pas de trace détaillée, celles qui échouent restent intégralement disponibles pour le diagnostic. Le compromis est clair — vous ne pourrez plus rouvrir une exécution réussie pour inspecter ses données — et il se compense en branchant un error workflow qui vous alerte dès qu'un échec survient, avec le contexte nécessaire.

EXECUTIONS_DATA_SAVE_ON_PROGRESS mérite un mot : à true, n8n écrit l'état de l'exécution en base au fil des nodes, ce qui permet de voir où en est une exécution longue mais multiplie les écritures. Il est à false par défaut ; ne l'activez que si vous en avez un besoin précis.

Ces réglages existent aussi par workflow, dans les settings du workflow (menu ⋯ → Settings) : Save successful production executions, Save failed production executions, Save manual executions, Save execution progress. C'est la granularité utile quand un seul workflow — typiquement le pipeline RAG qui ingère des documents — représente l'essentiel du volume : réglez-le à Do not save en cas de succès, et laissez le réglage global plus permissif pour les workflows légers.

Cas SQLite : supprimer ne rend pas l'espace

C'est le piège qui génère le plus d'incompréhension. Sur une installation par défaut, n8n utilise SQLite, et le fichier database.sqlite ne rétrécit jamais tout seul : quand des lignes sont supprimées (par la purge ou à la main), SQLite marque les pages comme réutilisables mais conserve la taille du fichier. Vous pouvez purger 90 % des exécutions et constater, perplexe, que le volume Docker pèse toujours autant.

La solution fournie par n8n est un VACUUM au démarrage :

DB_SQLITE_VACUUM_ON_STARTUP=true

Au prochain redémarrage, SQLite reconstruit le fichier en compactant l'espace libéré. Deux avertissements : l'instance est indisponible pendant toute la durée du VACUUM, et sur une base de plusieurs gigaoctets, l'opération peut être longue. Faites-le pendant une fenêtre creuse, après avoir sauvegardé le fichier, et pensez à repasser la variable à false ensuite si vous ne voulez pas payer ce coût à chaque redémarrage.

Soyons directs sur le fond : si votre database.sqlite atteint plusieurs gigaoctets, le VACUUM traite le symptôme, pas la cause. SQLite est parfait pour découvrir n8n et pour de petites charges, mais passé un certain volume d'exécutions, migrer vers PostgreSQL est la vraie solution — meilleure tenue en concurrence, outillage de mesure et de maintenance mature, sauvegardes propres. Notre guide sauvegarde et restauration d'un n8n self-hosted sur PostgreSQL couvre la mise en place côté base.

Cas PostgreSQL : mesurer, puis comprendre l'autovacuum

Sur PostgreSQL, le poids se concentre dans deux tables : execution_entity (les exécutions elles-mêmes) et surtout execution_data (les données des nodes). Pour mesurer précisément :

SELECT relname AS table,
       pg_size_pretty(pg_total_relation_size(relid)) AS taille_totale
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

Si execution_data domine largement ce classement — c'est presque toujours le cas — vous savez que le sujet est bien l'historique d'exécutions, pas autre chose.

Côté récupération d'espace, PostgreSQL se comporte différemment de SQLite, mais avec une subtilité comparable : l'autovacuum repère les lignes supprimées et rend leur espace réutilisable pour de nouvelles écritures, si bien qu'une base purgée régulièrement se stabilise au lieu de croître indéfiniment. En revanche, l'autovacuum ne rétrécit pas les fichiers sur le disque : l'espace reste alloué à la table. Pour rendre réellement l'espace au système, il faut un VACUUM FULL, qui réécrit la table — mais qui pose un verrou exclusif dessus pendant toute l'opération : n8n ne peut plus écrire d'exécutions pendant ce temps. Réservez-le à une fenêtre de maintenance planifiée, instance arrêtée ou trafic coupé, et uniquement si vous avez réellement besoin de récupérer le disque (après une purge massive ponctuelle, par exemple). En régime permanent, une purge bien réglée plus l'autovacuum suffisent : la base atteint sa taille de croisière et y reste.

Données binaires : sortez les fichiers de la base

Si vos workflows manipulent des fichiers (PDF, images, exports), vérifiez le mode de stockage binaire. Par défaut, n8n conserve les données binaires avec les données d'exécution — donc en base. Une seule variable change ce comportement :

N8N_DEFAULT_BINARY_DATA_MODE=filesystem

Les fichiers sont alors écrits sur le disque (dans le volume n8n) plutôt que dans la base, et la purge des exécutions nettoie les fichiers associés. Sur une instance qui traite des documents, c'est souvent la variable qui change le plus la trajectoire de la taille de base. Le fonctionnement complet, y compris les implications pour les sauvegardes et les architectures multi-instances, est détaillé dans notre guide du binary data.

La stratégie qui tient en production

En assemblant les pièces, la configuration de croisière d'une instance de production ressemble à ceci :

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    environment:
      # Flux : ne stocker que l'utile
      - EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
      - EXECUTIONS_DATA_SAVE_ON_ERROR=all
      - EXECUTIONS_DATA_SAVE_ON_PROGRESS=false
      # Stock : historique court
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
      - EXECUTIONS_DATA_PRUNE_MAX_COUNT=5000
      # Fichiers hors base
      - N8N_DEFAULT_BINARY_DATA_MODE=filesystem

Ce réglage repose sur un principe : l'historique d'exécutions sert au diagnostic récent, pas à la traçabilité longue durée. Les échecs sont conservés et un error workflow vous les signale en temps réel ; les succès ne laissent que leur trace statistique. Si un besoin métier exige de savoir durablement ce qui a été traité (quels clients, quels documents, quels montants), écrivez ces quelques champs dans une table dédiée depuis le workflow lui-même — quelques octets par exécution au lieu de mégaoctets, et une donnée réellement exploitable.

Reste à surveiller que la trajectoire est la bonne : la taille de la base fait partie des métriques à suivre dans le temps, au même titre que la mémoire ou les files d'attente — notre guide sur la supervision d'une instance n8n montre comment l'intégrer à un monitoring simple. Et si l'instance ralentit malgré une base saine, le sujet est ailleurs : voyez notre guide d'optimisation des performances des workflows.

Pièges fréquents

  • Croire que la purge rend l'espace disque : elle supprime des lignes, mais database.sqlite garde sa taille sans DB_SQLITE_VACUUM_ON_STARTUP=true, et PostgreSQL réutilise l'espace sans le rendre au système sans VACUUM FULL.
  • Lancer un VACUUM (SQLite) ou un VACUUM FULL (PostgreSQL) en pleine journée : l'un immobilise l'instance au démarrage, l'autre verrouille la table — les deux se planifient en fenêtre creuse, sauvegarde faite.
  • Activer EXECUTIONS_DATA_SAVE_ON_PROGRESS=true « au cas où » : chaque node écrit alors en base pendant l'exécution, ce qui multiplie les écritures pour un bénéfice rare.
  • Régler la purge globale mais oublier le workflow qui pèse : un seul pipeline RAG peut représenter l'essentiel du volume ; ses settings de workflow (Save successful production executionsDo not save) règlent le problème à la source.
  • Laisser les données binaires en base sur une instance qui traite des fichiers : N8N_DEFAULT_BINARY_DATA_MODE=filesystem change la trajectoire plus que n'importe quel réglage de purge.
  • Rester sur SQLite au-delà du raisonnable : compacter une base de plusieurs gigaoctets à chaque fois n'est pas une stratégie ; la migration vers PostgreSQL en est une.
  • Couper tout l'historique sans filet : SAVE_ON_SUCCESS=none sans error workflow ni journal métier, c'est voler à l'aveugle le jour où quelque chose se passe mal.

En résumé

Une base n8n qui gonfle n'est pas une anomalie, c'est le comportement par défaut : tout est stocké, pour tous les nodes, de toutes les exécutions. La réponse tient en trois étages — réduire le flux (EXECUTIONS_DATA_SAVE_ON_SUCCESS=none, SAVE_ON_ERROR=all, binaires sur le filesystem), limiter le stock (EXECUTIONS_DATA_MAX_AGE et EXECUTIONS_DATA_PRUNE_MAX_COUNT resserrés), et récupérer l'espace au bon moment (VACUUM SQLite au démarrage, autovacuum PostgreSQL en régime permanent). Comme le rappelait déjà l'étude d'Oliner et ses coauteurs, la question n'est jamais de tout garder, mais de savoir quoi conserver et pourquoi. C'est précisément la logique d'une piste d'audit digne de ce nom : garder une trace exploitable de ce qui a été traité — qui, quoi, quand, avec quel résultat — sans stocker des gigaoctets de payloads intermédiaires. Le Pack Conformité & Audit (149 €) fournit exactement cela : des workflows n8n prêts à l'emploi pour construire cette piste d'audit dédiée, légère et durable, pendant que votre historique d'exécutions reste ce qu'il doit être — un outil de diagnostic à durée de vie courte.

FAQ

Questions fréquentes

Pourquoi ma base de données n8n continue-t-elle de grossir alors que la purge automatique est activée ?

Deux explications dominent. La première : la purge supprime des lignes, mais le fichier de base ne rétrécit pas pour autant — SQLite conserve l'espace dans database.sqlite tant qu'un VACUUM n'a pas compacté le fichier, et PostgreSQL réutilise l'espace libéré pour de nouvelles écritures sans le rendre au système. La deuxième : la purge limite l'âge et le nombre des exécutions conservées, mais si chaque exécution stocke des payloads énormes (workflows IA, RAG, fichiers binaires en base), 10 000 exécutions récentes suffisent à peser lourd. Il faut alors réduire ce qui est stocké à la source avec EXECUTIONS_DATA_SAVE_ON_SUCCESS=none et N8N_DEFAULT_BINARY_DATA_MODE=filesystem.

Quelle est la différence entre EXECUTIONS_DATA_MAX_AGE et EXECUTIONS_DATA_PRUNE_MAX_COUNT ?

Les deux plafonds s'appliquent ensemble. EXECUTIONS_DATA_MAX_AGE fixe l'âge maximal d'une exécution conservée, en heures (336 par défaut, soit 14 jours) : au-delà, elle est purgée quel que soit leur nombre. EXECUTIONS_DATA_PRUNE_MAX_COUNT fixe le nombre maximal d'exécutions conservées (10 000 par défaut) : au-delà, les plus anciennes sont purgées même si elles n'ont pas atteint l'âge limite. Sur une instance qui exécute beaucoup, c'est souvent le plafond de nombre qui déclenche en premier ; sur une instance calme, c'est l'âge.

Est-ce risqué de mettre EXECUTIONS_DATA_SAVE_ON_SUCCESS=none en production ?

C'est un compromis assumé : vous perdez la possibilité de rejouer ou d'inspecter une exécution réussie après coup, mais vous divisez ce qui entre en base par le taux de succès de vos workflows — souvent l'essentiel du volume. La pratique courante consiste à garder EXECUTIONS_DATA_SAVE_ON_ERROR=all pour conserver tous les échecs, à brancher un error workflow pour être alerté immédiatement, et à consigner soi-même les quelques informations métier qui doivent survivre (identifiants traités, horodatage, résultat) dans une table ou un journal dédié plutôt que de compter sur l'historique complet des exécutions.

Bundle FlowKit Complet

269 €