n8n-data-tables-official について
n8nのワークフロー設計者向けに、小〜中規模の永続状態を内蔵Data Tablesで管理する方法を解説するガイドです。スキーマや操作、参照テーブル、イベント記録、行単位の重複排除に加え、実データベースを選ぶ基準も扱います。
主な機能
- 01列と行による永続データ保存
- 02行の挿入・更新・取得・削除
- 03upsertと行存在チェック
- 04重複排除と参照テーブルのパターン
- 05列型とリレーション設計
活用シーン
- 01安定した参照データの保存
- 02最近のイベントや監査記録の保存
- 03確認可能な重複排除状態の管理
- 04ワークフロー内での親子データのモデル化
MCP 対応
n8nのdata-table MCPツールを紹介し、MCPクライアントからテーブルデータを操作できることを説明します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ n8n-io/ skills --skill n8n-data-tables-officialインストール後、Claude Code で/n8n-data-tables-officialを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/DEDUP_PATTERNS.mdOPERATIONS.mdSCHEMA_DESIGN.md詳細
n8n Data Tables
Data Tables は、n8n に組み込まれた表形式のストレージです。n8n インスタンス内に実際のテーブルを作成し、列、型、行を使って、dataTable ノードとデータテーブル MCP ツールから CRUD 操作を行えます。
ローカルの永続状態に使用します。参照テーブル、最近のイベント、セッションごとのインベントリ、カウンター、冪等性の追跡、行単位のロジックや外部からの可視性が必要な場合の重複排除状態などに適しています(単純な「この値を見たことがあるか」の重複排除には Remove Duplicates ノードを使用します)。小規模から中規模のデータ量(数万行であれば問題ありません。数百万行の場合は実際の DB を使用してください)に適しています。
必ず守ること
- システム管理列と外部 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 ノードでできない作業はありません。(同じ Set ノードのアンチパターンが
n8n-expressions-officialで指摘されています。) -
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の「Storage format ≠ interface format」を参照してください。
デフォルトの列
すべての Data Table には、宣言の有無にかかわらず次の列があります。
| 列 | 型 | 動作 |
|---|---|---|
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を参照してください。
「Currently no items exist」というUIの挙動
SDKが手動モードの列マッピング(mappingMode: 'defineBelow')を保存すると、実行時にはデータが正しく保存されるにもかかわらず、n8n UIの「Values to insert」ペインが空(「Currently no items exist」)と表示される場合があります。ユーザーからInsertノードが「壊れているように見える」または「フィールドがない」と報告された場合は、UIの表示上の問題であることを伝え、列パラメーターの再読み込み(更新)ボタンを押してもらってください。スキーマが再読み込みされ、マッピングが表示されます。データ損失はなく、いつでも安全に実行できます。
よくあるパターン
外部IDによる重複排除
単純に「この値を以前に見たか」を重複排除する場合は、デフォルトでRemove Duplicatesノードの「items seen in previous executions」モードを使います。内部ストアを備えた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-officialを参照してください。Mergeによる合流と同じ形状の分岐については、n8n-node-configuration-officialのreferences/MERGE_NODE.mdを参照してください。
アンチパターン
| アンチパターン | 発生する問題 | 修正方法 |
|---|---|---|
| 入力を「整形する」ために Insert の前に Set ノードを配置する | 何のためにもならないノードが増えます。よくある Set のアンチパターンで、列を追加するとフィールド構成がずれていきます | Insert ノードの列ごとのスロットに直接マッピングするか、上流のフィールド名を変更して自動マッピングを有効にします |
create_data_table で id、createdAt、updatedAt を宣言する | エラーが発生するか、自動更新されないユーザー列でシステム列が隠されます | 宣言しないでください。これらの列はすでに存在します |
| アプリケーションにとって重要なデータを Data Tables に保存する | n8n が壊れると、データにアクセスできなくなります | 失うことのできないデータには、実際のデータベースを使用してください |
| Data Tables をアプリ横断のシステム・オブ・レコードとして扱う | n8n 以外の利用者との共有が難しく、クエリの操作性もよくありません | 実際のデータベースを使用してください |
自動生成される id をインスタンス間で安定した識別子として扱う | テーブルを再作成するとリセットされ、移植できません | システム間の参照には、ドメイン ID 列(arxivId、requestId)を使用してください |
| 外部キーのカスケードを前提にする | n8n はカスケードしないため、親を削除すると子が孤立します | 論理削除を行うか、参照整合性を保つクリーンアップワークフローを実行してください |
| 中間ノードで JSON が取り除かれた後に、直前のノードを参照する | Insert は「存在するはず」のフィールドに NULL を黙って書き込みます | 名前で安定した上流ノードを参照するか、NoOp/Merge の収束アンカーを使用してください(n8n-expressions-official と n8n-node-configuration-official の 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 が黙って書き込まれます。