n8nの実行履歴が数日で消える原因と自動削除の設定

n8n で「先週のあの実行はどう終わったか」を見ようとして実行の一覧を開いたら、数日前までしか残っていなかった、ということがあります。n8n は既定で14日分を残すと説明されていますが、実際にはそれより早く消えることがあります。この記事では、弊社の本番で実行履歴が数日で消えていた原因を n8n 本体のソースで確かめ、自動削除の設定の直し方と、たまった履歴を手で消す方法をまとめます。
この記事の結論
- n8n 2.19.2 の自動削除(prune。古い実行を定期的に消す仕組み)は、「終わってから
EXECUTIONS_DATA_MAX_AGE時間たった」か「件数がEXECUTIONS_DATA_PRUNE_MAX_COUNTを超えた」の、どちらか一方に当たれば実行を消します。既定は 336 時間と 10000 件です。 - 件数の上限はワークフローごとではなく、n8n 全体で1つです。数分おきに動くワークフローがいくつもあると、14日に届く前に件数の上限で消えます。弊社では 5.04 日、のちに約3.5日しか残っていませんでした。
- 直し方は、件数の上限を残したい日数ぶんに上げることと、見返さない成功の実行をワークフローごとに保存しないことです。環境変数を変えたら再起動し、n8n が読み込んだ値を、編集画面が読む設定(
/rest/settingsの応答)で確かめます。 - すでにたまった実行は、画面か API で消せます。SQLite は消してもファイルが縮まないので、最後に
VACUUMをかけます。
実際に起きたこと
弊社は n8n で140本を超えるワークフローを本番で動かしています。実行履歴の残り方では、3回つまずきました。
2026-07-01 データベースが 3.5GB に膨らんでいた
毎朝の点検に使っているスクリプトが、n8n の実行履歴を調べる手順で止まり、先へ進まなくなりました。調べると、n8n のデータベースのファイルが 3.5GB に膨らんでいて、点検のたびにそれを丸ごとコピーしようとしていました。
中身の大半は、execution_data の workflowData 列でした。n8n は実行ごとに、そのときのワークフロー定義の写しを保存します。弊社で動かしているワークフローのうち、ダッシュボードの画面にデータを返す1本だけで 2,657MB ありました。1回 430KB の実行が 6033 回分たまっていたのです。残っていた実行はすべて3日以内のもので、14日で消す日数の条件に当たるものはありませんでした。
このときは n8n を止めて sqlite3 .backup で控えを取りました。次に、ダッシュボード用のワークフローの成功の実行 5996 件と、もう1本の成功の実行 372 件を SQL で消しました。外部キーを有効にして、実行の中身の表からも一緒に消える形にしています。そのうえで2本とも、成功の実行を保存しない設定(saveDataSuccessExecution を none)にしました。最後に VACUUM をかけて、ファイルは 3.5GB から 76MB になりました。あわせて自動削除の環境変数を、既定と同じ値で明示しました。
2026-08-08 実行履歴が5日ほどしか残っていなかった
ワークフローを壊したときに戻せるよう、定義を毎日 git に保存する仕組みを作っていたときのことです。実行の表 execution_entity を数えると 10,192 件で頭打ちになっていて、残っていたのは 5.04 日ぶんだけでした。件数の上限 10000 が先に効き、336 時間(14日)には届いていませんでした。
件数の枠の大半は、5分おきに動く5本のワークフローが食っていました。5本とも 1,453 件ずつ残っていました。そのあおりで、お客様からの連絡に応えるワークフローの実行は、5日で 22 件しか残っていませんでした。
このときは上限を変えず、消える前に実行の記録を別の台帳へ写す仕組みを足しました。毎朝 8:40 に、いつ・どのワークフローが・成功したか失敗したか・何ミリ秒かかったかと、失敗したなら落ちたノードとエラー文(300字まで)だけを写します。実行の中身のデータは写さないので、1日約277KB、年に 101MB ほどで済みます。
2026-09-13 約3.5日で消えるようになっていた
検索まわりの自動化を点検したときに数え直すと、実行履歴は約3.5日で消えていました。日数の上限 336 時間より先に、件数の上限 10000 に当たっていたためです。これでは、週1回や月1回だけ動くワークフローが本当に動いたかを、n8n の画面で確かめられません。
そこで環境変数のファイル ~/.n8n-env.sh の EXECUTIONS_DATA_PRUNE_MAX_COUNT を 10000 から 60000 に上げ、05:12 に再起動して反映しました。
原因
ここからは、n8n 2.19.2 の本体のソースで確かめた内容です。
自動削除は「日数」と「件数」のどちらかで動く
設定の既定値は、@n8n/config の executions.config.js にあります。
this.pruneData = true;
this.pruneDataMaxAge = 336;
this.pruneDataMaxCount = 10_000;
this.pruneDataHardDeleteBuffer = 1;
上から順に、環境変数 EXECUTIONS_DATA_PRUNE、EXECUTIONS_DATA_MAX_AGE、EXECUTIONS_DATA_PRUNE_MAX_COUNT、EXECUTIONS_DATA_HARD_DELETE_BUFFER で変えられます。日数の上限は時間で数えます。336 時間は14日です。
消す対象を決めているのは、@n8n/db の execution.repository.js にある softDeletePrunableExecutions です。日数の条件は「終わった時刻(stoppedAt)が、今から pruneDataMaxAge 時間より前」です。
件数の条件は、上限が0より大きいときだけ作られます。実行を番号の新しい順に並べ、上限の件数ぶん飛ばした次の1件の番号を取り、その番号以下をすべて消す対象にします。
.skip(pruneDataMaxCount)
.take(1)
.orderBy('execution.id', 'DESC')
2つの条件は「または(orWhere)」でつながっています。どちらか一方に当たれば消えるので、日数を長くしても、件数の上限に先に当たればそこで消えます。公式ドキュメントも、どちらかの条件に当たったときに消す、と説明しています。
消さないものもあります。状態が new・running・waiting の実行(始まる前・実行中・待機中)と、注釈(タグや評価)が付いた実行です。
件数は n8n 全体で数える
件数の条件を作るクエリには、ワークフローで絞る条件がありません。除いているのは、注釈の付いた実行だけです。10000 件の枠を、すべてのワークフローで分け合う形です。数分おきに動くワークフローは、1本で1日に何百回も動きます。こうしたものが多いほど、ほかのワークフローの実行も早く押し出されます。
自動削除は2段階で消す
自動削除は一度には消しません。まず deletedAt に時刻を入れて「消す印」を付け(soft delete)、あとで本当に消します(hard delete)。
- 印付けは、既定で60分おきです(
EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL)。 - 本当に消すのは既定で15分おきです(
EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL)。印を付けてからEXECUTIONS_DATA_HARD_DELETE_BUFFER(既定1時間)たったものを、100 件ずつ消します。100 件以上見つかったときは、1秒後に続きを消します。 - この処理が動くのは、種類が main で、しかも leader の n8n だけです。
印付けが60分おきなので、件数がいつも上限ちょうどで止まるわけではありません。公式ドキュメントの設定例にも、上限の件数ちょうどまで減らすとは限らない、と書かれています。弊社で数えた 10,192 件が上限より少し多かったのも、こうした間隔があるためだと考えています。
「保存しない」設定の実行は、すぐ消える扱いになる
ワークフローの設定で成功の実行を保存しないようにすると、その設定は環境変数 EXECUTIONS_DATA_SAVE_ON_SUCCESS より優先されます。ワークフローの設定が無いときと DEFAULT のときだけ、環境変数の値を使います(to-save-settings.js)。
保存しない設定の本番の実行は、終わった時点で deleteInFlightExecution が呼ばれます。自動削除が有効なら、deletedAt には「今から猶予の時間(既定1時間)を引いた時刻」が入ります。次の hard delete でそのまま消える扱いなので、件数の枠を長く占めることはありません。
SQLite では消してもファイルは縮まない
公式ドキュメントには、既定の SQLite を使っている場合、消した分の領域は自動では空かず、次の実行データに使い回されると書かれています。空けるには、DB_SQLITE_VACUUM_ON_STARTUP を設定するか、自分で VACUUM を実行します。ソースでも、この設定の既定は false です。true のときだけ、起動時に VACUUM; を流しています(commands/start.js)。
直し方
1. いま何件・何日ぶん残っているかを測る
まず現状を数えます。SQLite なら、データベースを読み取り専用で開いて次を流します。弊社の環境では、ファイルは ~/.n8n/database.sqlite です。
# 残っている件数と、いちばん古い・新しい実行の開始時刻(UTC)
sqlite3 -readonly ~/.n8n/database.sqlite \
"SELECT COUNT(*), MIN(startedAt), MAX(startedAt) FROM execution_entity WHERE deletedAt IS NULL;"
# どのワークフローが枠を食っているか(上位10本)
sqlite3 -readonly ~/.n8n/database.sqlite \
"SELECT workflowId, COUNT(*) AS n FROM execution_entity WHERE deletedAt IS NULL GROUP BY workflowId ORDER BY n DESC LIMIT 10;"
startedAt は UTC で入っています。日本時間で読むなら9時間足します。時刻のずれでつまずいた話は「n8nのスケジュールが13時間ずれる原因と直し方|タイムゾーン設定」にまとめています。
いちばん古い実行の時刻と今の差が、いま実際に残っている日数です。件数が上限の近くで止まっていて、日数が14日より短ければ、件数の上限に先に当たっています。
2. 件数の上限を決める
残る日数は、およそ「件数の上限 ÷ 1日に増える実行の数」で決まります。1日に増える数は、手順1で測った件数を、残っている日数で割ると出ます。上限は「残したい日数 × 1日に増える実行の数」より大きくします。件数の上限を0にすると件数では消さなくなり、日数の条件だけが残ります。
弊社は件数を 60000 にし、日数は既定の 336 時間(14日)のままにしました。公式ドキュメントの例は、日数 168 時間・件数 50000 です。
# npm で動かしている場合(n8n の起動前に読み込む環境変数のファイル)
export EXECUTIONS_DATA_PRUNE=true
export EXECUTIONS_DATA_MAX_AGE=336
export EXECUTIONS_DATA_PRUNE_MAX_COUNT=60000
# Docker Compose の場合
n8n:
environment:
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=336
- EXECUTIONS_DATA_PRUNE_MAX_COUNT=60000
上限を上げれば、データベースはそのぶん大きくなります。1件あたりのデータが大きいワークフローがあるなら、次の手順で先に減らしておきます。
3. 見返さない成功の実行は保存しない
画面にデータを返すだけのワークフローや、数分おきに状態を見るだけのワークフローは、成功した実行を残しても見返すことがほとんどありません。こうしたものは、ワークフローの設定で成功の実行を保存しないようにします。
- ワークフローを開き、右上の三点のアイコンから Settings を開きます。
- 「Save successful production executions」を、保存しない側にします。
- 「Save failed production executions」は、保存する側のままにします。失敗は後から追えるようにしておきます。
API でワークフローを更新しているなら、settings に次を入れます。値は all か none です。
"settings": {
"executionOrder": "v1",
"saveDataSuccessExecution": "none",
"saveDataErrorExecution": "all"
}
ただし、成功の実行を保存しないと「ちゃんと動いたか」を n8n の画面で確かめられなくなります。週1回だけ動くような、動いたこと自体を確かめたいワークフローには使いません。
4. 再起動して、n8n が読み込んだ値を確かめる
環境変数のファイルを書き換えたら、n8n を再起動します。再起動は、実行中のワークフローが無いときに行います。弊社は、Webhook の受信や実行中の実行が30分無いことを確かめてから再起動する、小さなスクリプトを使いました。
値が入ったかは、n8n の編集画面が読み込む設定で確かめます。n8n はここで画面用の設定をまとめて返し、その中の pruning が自動削除の設定です。
- n8n にログインして、編集画面を開きます。
- ブラウザの開発者ツールを開いて Network(ネットワーク)のタブを選び、ページを読み込み直します。
- 通信の一覧から
settingsを選び、応答(Response)の中のpruningを見ます。
# 上限を 60000 にしていれば次のとおり
"pruning":{"isEnabled":true,"maxAge":336,"maxCount":60000}
アドレス欄に /rest/settings を直接入れて開くのはやめてください。n8n はログインの印と一緒に、どのブラウザからの通信かを示す印(browser-id という見出し)も確かめています。編集画面はこの印を付けて設定を読みますが、アドレス欄から開いたときは付きません。印が合わない通信では、ログインの cookie が消され、ログインしていない人向けの設定だけが返ります(この項目は出ません)。弊社は n8n 2.19.2 のソース(auth.service.js の validateBrowserId と createAuthMiddleware、server.js の configureSettingsRoute)で確かめました。
ここに出るのは、ファイルに書いた値ではなく、動いている n8n が読み込んだ値です。N8N_ENDPOINT_REST で rest の部分を変えている場合は、その値に置き換えます。環境変数のファイルと再起動の扱いは、「n8nのCodeノードで「access to env vars denied」が出る原因と直し方」でも触れています。
5. すでにたまった実行を手で消す
手順3の「保存しない」設定は、実行が終わるときに見られます。設定する前に保存された実行は、そのまま残ります。日数か件数の条件で消えるのを待てないときは、手で消します。
- 画面:実行の一覧(Executions)で、消したい実行を選んで消します。終わった実行をまとめて選ぶこともできます。1件だけなら、実行を開いた画面のごみ箱のアイコン(Delete this execution)でも消せます。
- API:公開 API の
DELETE /api/v1/executions/{id}で、1件ずつ消せます。実行中のものは「Cannot delete a running execution」で断られます。
curl -X DELETE "https://n8n.example.com/api/v1/executions/XXXX" \
-H "X-N8N-API-KEY: XXXX"
画面と API のどちらで消しても、印付けを待たずにその場で消えます。このとき n8n は、データベースの行と一緒に、バイナリのデータや、データベースの外のファイルに置いた分も消します。
SQL で直接消す方法もあります。弊社が 2026-07-01 にとったのは、こちらの方法です。n8n を止めて控えを取ってから、1回の sqlite3 の中で外部キーを有効にして消します。
# n8n を止めてから(XXXX はワークフローの ID)
sqlite3 ~/.n8n/database.sqlite \
"PRAGMA foreign_keys=ON; DELETE FROM execution_entity WHERE workflowId='XXXX' AND status='success';"
実行の中身の表 execution_data は、実行の表に外部キーでつながっていて、消すと連れて消える設定(ON DELETE CASCADE)です。n8n は接続を開くたびに PRAGMA foreign_keys = ON を流しています。ソースの注記にも、これで SQLite でも連れて消える設定が働く、とあります。自分で消すときも、この1行を先に流します。ただし SQL で消すと、データベースの外のファイルに置いた分(バイナリのデータなど)は残ります。
直ったかを確かめる
- 再起動の直後:有効なワークフローの数が再起動の前と同じか、エラーが出ていないかを見ます。弊社では有効な144本がそろい、再起動後15分でエラーは0でした。
- 設定:手順4のとおり、編集画面の通信の中の
settingsの応答で、maxCountが新しい値になっているかを見ます。 - 数日後:手順1のクエリをもう一度流します。件数が古い上限(10000)を超えて増えていき、いちばん古い実行の時刻が前より昔までさかのぼっていれば、新しい上限が効いています。
- 日数の条件:いちばん古い実行が 336 時間(14日)前あたりで止まるようになれば、今度は日数の条件で消えています。
- 週1回のワークフロー:実行の一覧に、前の週の実行が残っているかを見ます。
それでも直らないとき
新しい値で起動していない
n8n を立ち上げる経路が複数あると、片方だけ環境変数のファイルを読まずに起動することがあります。弊社では、落ちたときに n8n を立て直す見張りのスクリプトの起動の仕方を直し、そちらも環境変数のファイルを読むようにしました。プロセスの環境変数を見て確かめるなら、起動用のラッパー(screen など)ではなく node の実体のプロセスを見ます。pgrep で最初に見つかった1件を見ると、ラッパーの方を拾うことがあります。
件数を上げたらデータベースが大きくなりすぎた
大きさは件数だけでなく、1件あたりのデータの量でも決まります。弊社の例では、1回 430KB の実行を何千回も保存していたワークフローが原因でした。縮めるときは、次の順で進めます。
- 手順3で、そのワークフローの成功の実行を保存しないようにします。これで、新しく増える分が止まります。
- 手順5で、すでに保存された実行を消します。消さずに
VACUUMをかけても、残っている実行の分は縮みません。 - n8n を止めて控えを取り、壊れていないことを確かめてから
VACUUMをかけます。
# n8n を止めてから
sqlite3 ~/.n8n/database.sqlite ".backup '/path/to/backup.sqlite'"
sqlite3 /path/to/backup.sqlite "PRAGMA integrity_check;"
sqlite3 ~/.n8n/database.sqlite "VACUUM;"
特定の実行だけは長く残したい
注釈(タグや評価)を付けた実行は、自動削除の対象から外れます。障害を調べるのに使った実行など、残したいものにだけ付けます。付ける場所は、実行を開いた画面の評価のボタンなどの欄です。ただし、この欄はライセンスで実行の高度な絞り込みの機能(feat:advancedExecutionFilters)が有効なときだけ出ます。欄が出ていない n8n では、画面から注釈を付けられません。
何か月も前の実行を追いたい
n8n の中に何か月分も残そうとすると、データベースが重くなります。弊社は、実行の事実だけを毎朝別の台帳へ写す方法にしました。写すのは日時・ワークフロー・成否・所要時間・失敗したノードとエラー文で、中身のデータは写しません。
写すときは、startedAt が UTC なので台帳では日本時間に直します。また、n8n の実行データは flatted という形式(すべての文字列を配列の番号に置き換えた JSON)なので、エラー文は番号をたどり直して取り出します。台帳のいちばん新しい番号とデータベースのいちばん古い番号のあいだが飛んでいたら、取りこぼしとして知らせが届くようにしています。
まとめ
- n8n の実行履歴は、既定では「336 時間たった」か「件数が 10000 を超えた」のどちらかで消えます。
- 件数の上限は n8n 全体で1つです。数分おきに動くワークフローが多いと、14日に届く前に件数で消えます。
- まず件数と、いちばん古い実行の時刻を測ります。そのうえで
EXECUTIONS_DATA_PRUNE_MAX_COUNTを、残したい日数ぶんに上げます。 - 見返さない成功の実行はワークフローごとに保存しないようにします。書き換えたら再起動し、編集画面の通信(
settingsの応答)で読み込まれた値を確かめます。 - たまった実行は画面か API で消し、SQLite は n8n を止めて
VACUUMでファイルを縮めます。
参考にした公式ドキュメント
n8nの点検と構築のご相談
「先週のワークフローが動いたか分からない」「実行履歴が消えていて止まった原因を追えない」といったn8nの運用の点検や、実行の記録を残す仕組みづくりをお引き受けしています。






