n8n-data-tables について
n8n-data-tablesは、n8n組み込みのテーブルストレージでワークフローの状態を保持するためのエージェントスキルです。スキーマ設計やCRUD操作に加え、検索、重複排除、イベント記録での活用方法を説明します。
主な機能
- 01状態保持のためのテーブルストレージ
- 02CRUD操作のガイド
- 03スキーマと列の設計
- 04検索・重複排除・イベント記録のパターン
- 05公開前のData Table検証
活用シーン
- 01ワークフロー用の検索データ保持
- 02重複排除や冪等性の状態追跡
- 03最近のイベントの記録と検索
MCP 対応
テーブルの作成や操作に使うData Table MCPツールと、n8nの`dataTable`ノードについて説明します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ n8n-io/ skills --skill n8n-data-tablesインストール後、Claude Code で/n8n-data-tablesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/DEDUP_PATTERNS.mdOPERATIONS.mdSCHEMA_DESIGN.md詳細
n8n データテーブル
データテーブルは、n8n に組み込まれた表形式ストレージです。n8n インスタンス内に実際のテーブルを作成し、列、型、行を管理できます。また、dataTable ノードとデータテーブル MCP ツールを使って CRUD 操作を行えます。
ローカルの永続状態に使用します。たとえば、参照テーブル、最近のイベント、セッションごとの在庫、カウンター、冪等性の追跡、行単位のロジックや外部からの可視性が必要な場合の重複排除状態などです(「この値を見たことがあるか」だけを確認する単純な重複排除には、Remove Duplicates ノードを使用します)。小規模から中規模のデータ量に適しています(数万行は問題ありませんが、数百万行なら実際のデータベースを使用してください)。
必須事項
- システム管理列と外部 ID。 すべてのテーブルには、
id(bigserial)、createdAt、updatedAtの 3 つの列が自動的に存在します。create_data_tableでこれらを宣言しないでください(エラーになるか、システム列と重複します)。挿入時にこれらを書き込まないでください。外部由来のドメイン識別子(arxivId、stripeCustomerId、requestId)には、別の列を追加し、それを使って重複排除や検索を行います。 - 列にはプリミティブ型のみを使用し、ネストされたデータには
stringと_objectの接尾辞を使用します。 JSON/オブジェクト/配列の列型はありません。ネストされたデータ(配列、解析済みオブジェクト)には、string列を使用し、書き込み時にJSON.stringify(...)、読み込み時にJSON.parse(...)を使います。列名には_objectを付けます(例:keyInsights_object)。この接尾辞は、読み取り側に解析が必要であることを伝える規約です。詳しくはreferences/SCHEMA_DESIGN.mdを参照してください。
推奨する既定の方針
-
フィールドを変更するために、Data Table ノードの前に Set ノードを追加しないでください。 Data Table ノードの列ごとの式入力欄は Set ノードのフィールドと同じように強力なため、Set ノードでは Data Table ノード単体でできることを重複して行うだけです(
n8n-expressionsでも同じ Set ノードのアンチパターンが指摘されています)。 -
n8n の列名の大文字小文字の形式に合わせ、camelCase を使用します。 自動管理される列は camelCase(
createdAt、updatedAt)のため、ユーザー列も同じ形式にすると読みやすくなります(arxivId、paperId、taxRate)。同じクエリに異なる形式が混在すると(createdAt >= ... AND arxiv_id eq ...)、タイプミスのように見えます。文字列化したデータを格納する列には、必ず_objectの接尾辞を付けてください(keyInsights_object)。アンダースコアは大文字小文字の形式ではなく、規約を示すマーカーです。 -
作成/更新後に
get_workflow_detailsでcolumnsパラメーターを確認してください。 手動マッピングモードの UI には、実際にはデータが失われていないのに「Currently no items exist」と表示される仕様上の癖があります。JSON を確認すれば、何が保存されているかを確かめられます。 -
データの形に合う場合は、リレーショナル設計が有効です。 実際に親子関係があるデータ(論文 → 要約、顧客 → 注文)では、
idで親を参照し、列名を明示し(paperId、customerId)、ワークフローのロジックで整合性を確保します。重複排除、参照、監査など、モデル化する関係がないフラットな用途に無理に適用しないでください。 -
ストレージ形式とインターフェース形式は異なります。
_objectフィールドはサブワークフローから返す前に解析してください。呼び出し元に、独自に解析しなければならない文字列化されたデータを渡してはいけません。詳しくはreferences/SCHEMA_DESIGN.mdの「ストレージ形式 ≠ インターフェース形式」を参照してください。
既定の列
すべてのデータテーブルには、宣言の有無にかかわらず、次の列があります。
| 列 | 型 | 動作 |
|---|---|---|
id | bigserial / number | 自動インクリメントされる主キーです。n8n が挿入時に割り当てるため、書き込みはできません。挿入レスポンスに含まれます。 |
createdAt | timestamp | 挿入時に自動設定されます。 |
updatedAt | timestamp | 更新のたびに自動更新されます。 |
実際には、次のようにします。
create_data_tableでこれらを宣言しないでください。 すでに存在します。- 独自のタイムスタンプ列を作成せずに、クエリでこれらを使用します。 「今日作成されたもの」:
createdAt >= '<today ISO>'。「前回の同期以降に更新されたもの」:updatedAt >= $('Last Sync').item.json.timestamp。 - システム間の識別子として使用しないでください。 自動生成される
idは内部用であり、テーブルの再作成やインスタンスの移行でリセットされます。ドメイン識別子には、独自の列を使用してください。
形状に合う場合のリレーショナル設計
Data Tables では外部キーを強制できませんが、データが実際に親子関係になっている場合は、テーブル間で親子データをモデル化できます。ただし、整合性の確保は n8n ではなく、皆さんの責任です。
- 親行は
idで参照します。 子テーブルの列に親のidを格納します。 - 列名で参照関係を明示します。
paperId、customerId、eventIdのような名前にすると、関係が明確になります。 - ワークフローのロジックで整合性を確保します。 子を挿入する前に、親を検索します。親を削除する前に、子をどうするか(削除、孤立化、アーカイブ)を決めます。n8n が連鎖処理することはありません。
- 古い参照に注意します。 削除済みの親を指す子は、気づきにくい不具合になります。論理削除するか、クリーンアップのワークフローを実行してください。
複雑なリレーショナル構造(3 つ以上のテーブルを結合したり、トランザクションで書き込んだりする場合)には、実際の SQL DB を使用してください。
操作:用途別の使い分け
| 操作 | 使用する場面 |
|---|---|
insert | 常に追加します。新しい行に n8n が id を割り当てます。 |
upsert | 「新規なら追加、既存なら更新」します。存在を判定するための matchType とフィルターが必要です。 |
update | 「このフィルターに一致する行を変更」します。一致する行がなくても挿入はしません。 |
get | フィルターに一致する行を取得します(0 行以上を返します)。orderBy、limit、returnAll をサポートします。 |
deleteRows | フィルターに一致する行を削除します。 |
rowExists / rowNotExists | 入力アイテムに対して真偽値形式のフィルターを適用します。重複排除の分岐によく使われます。 |
操作全般(フィルター構文、matchType、並べ替えパターン)については、references/OPERATIONS.md を参照してください。
「現在、アイテムはありません」という UI の癖
SDK が手動モードの列マッピング(mappingMode: 'defineBelow')を保存すると、実行時にはデータが正しく保存されるにもかかわらず、n8n UI の「挿入する値」ペインが空(「現在、アイテムはありません」)に表示されることがあります。ユーザーから Insert ノードが「壊れているように見える」または「フィールドがない」と報告された場合は、UI の表示上の問題なので、列パラメーターの再読み込み(更新)ボタンを押せばスキーマが再表示され、マッピングも表示されると伝えてください。データは失われず、いつでも安全に実行できます。
よくあるパターン
外部 ID による重複排除
単純に「この値を見たことがあるか」を重複排除する場合は、デフォルトで Remove Duplicates ノードの「以前の実行で見たアイテム」モードを使用してください。内部ストアを使う 1 ノードだけの解決策で、スキーマの管理も不要です。重複排除の状態を実テーブルに保存する理由がある場合に限り、Data Tables の使用を検討してください。
- 重複排除の状態を検索または確認する場合。 ダッシュボード、監査、「過去 1 週間に処理したものは何か?」など。
- 一致時に行単位のロジックが必要な場合。 カテゴリーごとの TTL(「カテゴリー A は 30 日後、カテゴリー B は 7 日後に期限切れ」)、保存された状態に基づく条件付きの再処理、ステータス列に基づく分岐など。
Remove Duplicatesの履歴ストアでは表現できない、テナント単位またはユーザー単位の名前空間が必要な場合。
この条件を満たす場合:
[Source: { arxivId, ... }]
↓
[Data Table Get: filter arxivId eq $json.arxivId, limit 1]
↓
[IF: result has items?]
├── Yes → [Skip, or apply row-level logic from the stored row]
└── No → [Process] → [Data Table Insert: { arxivId, ...rest }]
パターン全般(upsert、rowNotExists、Get+IF、冪等性キー)については、references/DEDUP_PATTERNS.md を参照してください。
ルックアップテーブル
安定した参照データ(国 → 税率、プラン → 機能フラグ)。n8n UI で編集し、ワークフローが実行時に読み込みます。
[Data Table Get: filter country eq $json.country, limit 1]
↓
[Use the looked-up row's taxRate, etc.]
最近のイベント/監査証跡
追記専用で挿入し、後で検索します。
[Workflow event] → [Data Table Insert: { userId, eventType, payloadSummary }]
createdAt があれば、「過去 1 時間の最近のイベント」を独自のタイムスタンプなしで簡単に取得できます。
参考ファイル
| ファイル | 参照する場面 |
|---|---|
references/SCHEMA_DESIGN.md | 列/型の設計、外部キーなしのリレーショナルパターン、マッピングモード(defineBelow と autoMapInputData)、Data Tables が適さないケース |
references/OPERATIONS.md | 操作全般(insert/upsert/update/get/delete/rowExists)、フィルター構文、matchType、orderBy |
references/DEDUP_PATTERNS.md | 冪等性キー、RemoveDuplicates ノードと Data Table による重複排除、検索してから挿入する方法と upsert |
式の扱い方($json と $('Node Name').item.json の使い分け、Set ノードのアンチパターン)については、n8n-expressions を参照してください。Merge による合流と同じ形状の分岐については、n8n-node-configuration の references/MERGE_NODE.md を参照してください。
アンチパターン
| アンチパターン | 問題点 | 対処方法 |
|---|---|---|
| 「入力を整形する」ために Insert の前に Set ノードを置く | 余計なノードが増えるだけで、典型的な Set のアンチパターンです。列を追加するとフィールド構造がずれてしまいます | Insert ノードの列ごとのスロットに直接マッピングするか、上流のフィールド名を変更して自動マッピングを有効にします |
create_data_table で id、createdAt、updatedAt を宣言する | エラーが発生するか、自動更新されないユーザー列によってシステム列が隠されます | 宣言しないでください。これらの列はすでに存在します |
| アプリケーションに不可欠なデータを Data Tables に保存する | n8n が壊れると、データにアクセスできなくなります | 失うことのできないデータには、実際の DB を使用してください |
| 複数のアプリで共有するシステム・オブ・レコードを Data Tables に保存する | n8n 以外の利用者との共有が難しく、クエリの扱いも不便です | 実際の DB を使用してください |
自動生成される id をインスタンス間で安定した識別子として扱う | テーブルを再作成するとリセットされ、移植できません | システム間の参照には、ドメイン ID の列(arxivId、requestId)を使用してください |
| 外部キーのカスケードを前提にする | n8n はカスケード削除を行わないため、親を削除すると子が孤立します | 論理削除を使用するか、参照整合性を維持するクリーンアップワークフローを実行してください |
| 直前のノードの json が中間ノードで削除されているのに、そのノードを参照する | 本来存在するはずのフィールドに NULL が書き込まれても、エラーが表示されません | 名前で安定した上流ノードを参照するか、NoOp/Merge の合流アンカーを使用してください(n8n-expressions および n8n-node-configuration の references/MERGE_NODE.md を参照) |
| 手動マップモード+Set ノードで「現在、アイテムがありません」を解決しようとする | 何も解決しません。これは UI の問題で、役に立たない Set ノードを追加しただけです | get_workflow_details で columns.value にマッピングがあることを確認してください。実行時には問題ありません。列パラメーターの再読み込みボタンを押して UI にフィールドを表示するよう、ユーザーに伝えてください。 |
公開前の検証
Data Tables を使用するワークフローを作成または更新した後、次の項目を確認してください。
validate_workflowが成功すること。get_workflow_detailsを実行し、各 Data Table ノードのcolumnsを確認すること。valueと(手動マップの場合は)schemaの両方に値が設定されていること。- ピン留めされたデータで
test_workflowを実行すること。Insert の応答にid、createdAt、updatedAtが含まれていること。 - UI または後続の Get で実際の Data Table の内容を確認し、列に NULL が書き込まれていないこと。
特に、Insert を新たに設定した最初のときは、手順 4 を必ず実施してください。コンテキストを削除する中間ノード+手動マップ+UI の問題によって、列に NULL が書き込まれても気づかないことがあります。