n8n-subworkflows-official について
n8n-subworkflows-officialは、n8nで再利用可能なサブワークフローを設計するためのスキルです。契約、状態管理、検索方法、ロジックを抽出する判断を扱います。
主な機能
- 01再利用と抽出の判断指針
- 02入出力契約の設計
- 03ステートレス・ステートフルのパターン
- 04タグとキーワードによる検索
- 05ミドルウェアと非同期呼び出しのパターン
活用シーン
- 01複数のワークフローで汎用ロジックを再利用
- 02ステップを分離して個別テストや置き換え
- 03Webhookに検証やレート制限を追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ n8n-io/ skills --skill n8n-subworkflows-officialインストール後、Claude Code で/n8n-subworkflows-officialを入力して読み込まれたか確認します。
同梱ファイルreferences/NAMING_AND_DISCOVERY.mdreferences/SUBWORKFLOW_PATTERNS.md
詳細
n8n サブワークフロー
サブワークフローは再利用可能な関数です。Execute Workflow Trigger で入力パラメーターを宣言し、本体で処理を行い、最後のノードで出力を返します。呼び出し元は、ほかのノードと同じように呼び出します。
この考え方により、関数としての利点であるカプセル化、再利用、テスト容易性、置き換え可能性を活かせます。これは n8n における主要な再利用手段ですが、残念ながら十分に活用されていません。
サブワークフローがないと、同じロジックが複数のワークフローに重複して実装されます。バグ修正を複数箇所で行うことになり、そのうちの一つを見落とすと、「同一」のコピーに差異が生じていきます。
必須事項
- 作成する前に検索してください。 汎用的な問題を処理するロジックを書く前に、既存のサブワークフローがないか確認してください。タグ(
search_workflows({ tags: ['subworkflow'] })、ドメインタグ)やキーワード(query: '<keyword>')で絞り込みます。タグは検索手段です(n8n 2.27.0+)。 Execute Workflow Triggerでは、パススルーではなく、型付きフィールドを使って「Define Below」を選択してください。 エージェントツール(fromAi)や構造化された呼び出し元から値を渡せるのは、「Define Below」だけです。例外は2つあります。(a)サブワークフローがバイナリデータを受け取る必要がある場合(その場合、エージェントツールとして直接接続できません)、または(b)サブワークフローに入力がまったくない場合(「Define Below」では少なくとも1つのフィールドが必要です)。下記の「サブワークフローの入出力」を参照してください。
基本方針
- 再利用可能なものはすべてサブワークフローにします。 ほかの場所でも必要になりそうな論理的なまとまりは、切り出してください。例外は、単純なラッパー(ロジックのないHTTP呼び出し1回)と、呼び出し元に密接に結び付いた処理です。
- 純粋なロジックは、ステートレスをデフォルトにします(入力 → 出力、外部状態なし)。状態を扱うロジックでは、明確な契約(ORM/リポジトリパターン)に基づいて操作を抽象化する、意図的にステートフルなサブワークフローを作成してください。避けるべきなのは「意図しない」状態です。たとえば、「検証」サブワークフローがひそかにログテーブルへ書き込むようなケースです。
- 検索できるようにタグを付けます。すべてのサブワークフローに
subworkflow、ドメインタグ(customer)、および/またはtoolを付けます。search_workflows({ tags })の絞り込みにはタグが使われます。名前は簡潔で説明的なものにします(Parse RFC2822 date)。references/NAMING_AND_DISCOVERY.mdを参照してください。 - 説明文にキーワードを含めます。 入出力の形状と代表的な用語を記載し、多様な検索クエリで見つかるようにします。
- 入力契約が本質的に異なる場合は分割します(バイナリとJSON、同期と非同期、異なる認証方式など)。パススルーと内部の分岐で、異なる契約を1つのトリガーに無理にまとめないでください。「入力形状による分割」については、
references/SUBWORKFLOW_PATTERNS.mdを参照してください。
判断基準:これはサブワークフローにすべきですか?
About to write a chunk of logic?
├── Could this plausibly be needed in another workflow?
│ ├── Yes → extract to sub-workflow
│ └── No → keep inline
│
├── Is this chunk >5 nodes and conceptually one thing?
│ └── Extract if you want testability, isolation, or reuse; if it's only for a cleaner canvas, group it inline instead (see below).
│
├── Is this chunk dealing with a generic concern (auth, retry, parsing, formatting)?
│ └── Almost certainly extract. These are the canonical reusable sub-workflows.
│
└── Is this chunk doing one HTTP call with no logic around it?
└── Don't extract. Extra workflow boundary for nothing.
動機がキャンバスをすっきりさせることだけであり(再利用、分離、テスト容易性、エージェントツールが目的ではない場合)、読みやすさだけを目的としたセクション分けにはキャンバスノードグループが適しています。より高速で(呼び出しごとのサブ実行が不要)、よりシンプル(入出力契約が不要)であり、ロジックはインラインのままです。セクションが接続されている位置にグループを配置し、トリガーを含めず、各方向に含めるメンバーは最大1つにします(n8n-workflow-lifecycle-official の references/NODE_GROUPS.md)。分岐が多すぎるセクションは、ステージ全体をグループ化せずに残すのではなく、条件を満たす小さなまとまりに分割してください(付箋は注釈にはなりますが、グループにはなりません)。再利用、分離、独立したテスト、またはエージェントツールが本当に必要な場合に限り、サブワークフローに切り出してください。n8n-workflow-lifecycle-official の「読みやすさ」を参照してください。
ステートレスとステートフルのサブワークフロー
どちらも一級の選択肢です。選択の基準は、意図とカプセル化です。
ステートレス
入力を受け取り、出力を返します。入出力以外のI/Oはありません。純粋なロジックのデフォルトです。
例:
Parse RFC2822 date(タグsubworkflow)。入力:日付文字列。出力:ISO日付またはエラー。Compute MRR from subscription(タグsubworkflow)。入力:サブスクリプションオブジェクト。出力:MRRの数値。Format invoice as HTML(タグsubworkflow)。入力:請求書データ。出力:HTML文字列。
同じロジックが必要になったら、副作用の発生を気にせず呼び出せます。
ステートフル(意図的)
明確な入出力の契約のもとで、外部の状態を読み取る、または書き込みます。リポジトリパターンに似ています。サブワークフローが状態操作を抽象化するため、呼び出し側は実装ではなくドメインの用語で考えられます。
例:
Get customer by id(タグcustomer)。入力:ID。出力:顧客オブジェクト、または{ ok: false, error: 'not_found' }。DB を読み取ります。Write customer billing record(タグcustomer、billing)。入力:レコード。出力:{ ok: true, id }。DB に書き込みます。Append audit event(タグaudit)。入力:イベント。出力:{ ok: true, eventId }。ログストアに書き込みます。Send to on-call(タグnotification)。入力:チャンネル、メッセージ。出力:{ ok: true, messageId }。Slack/SMTP を呼び出します。
これらをサブワークフローとして構築する利点は次のとおりです。
- 呼び出し側はストレージ(
SELECT * FROM customers ...)ではなく、ドメインの用語(get customer by id)で考えられます。 - 呼び出し側に手を加えずに、その背後にあるストア/API(Postgres → Supabase、ネイティブノード → HTTP)を差し替えられます。
- 冪等性、再試行、検証をサブワークフローの責任として、1 か所に集約できます。
避けるべきなのは、意図せず発生する状態変更です。純粋な処理として名前や説明が付けられたサブワークフローが、ひそかにログテーブルへ書き込むようなケースです。安全に再試行したり組み合わせたりできると合理的に想定していた呼び出し側を、予期せず巻き込みます。副作用を契約の一部にする(名前を変え、説明し、結果を返す)か、外部に移してください。
抽出するタイミング
主な兆候は 2 つあります。
1. 概念上の一貫性
ノードのまとまりが 1 つの論理的な処理を担っている場合、再利用されていなくても、次の目的で抽出する価値があります。
- テスト容易性。 データを固定して、サブワークフロー単体で実行できます。
- 置き換えやすさ。 実装を差し替えても、呼び出し側への影響が波及しません。
読みやすさだけを理由に抽出する必要はありません。ノードグループを 1 つのラベル付きボックスにまとめれば、より手軽に 5 つのノードを 1 つにできます(サブ実行も入出力の契約もありません)。テスト容易性、置き換えやすさ、または再利用も必要な場合に抽出してください。
1.5 ファイア・アンド・フォーゲットの監査ログパターン
監査ログは、ファイア・アンド・フォーゲット型のステートフルパターンを具体的に示すために、ここで取り上げています。ユーザーから依頼されていない限り、ワークフローに監査ログを追加しないでください。 このパターン自体(サブワークフローを非同期で起動し、完了を待たないこと)は、メトリクスや通知など、あらゆる副次的な記録に応用できます。
意図的にステートフルな監査ログのサブワークフローを Execute Workflow の waitForSubWorkflow: false を指定して呼び出すと、呼び出し側は書き込みの完了を待たずに済みます。
Caller ──→ [Execute Workflow: DB audit log]
{ title: 'Email Confirmation Received',
description: <serialized data> }
waitForSubWorkflow: false
↓ (caller continues immediately)
──→ [Continue with next step]
サブワークフローはタイトルと説明を受け取り、ログテーブル(または Slack、あるいはその両方)に書き込んで終了します。呼び出し側は待ちません。監査ログは副次的な記録であり、クリティカルパスではありません。
ユーザーから依頼された場合は、意味のある状態遷移(「確認メール受信」「ユーザー確認済み」「処理開始」「適格性の判定」)のたびに起動し、ログからタイムラインを再構成できるようにします。
役立つ理由は次のとおりです。
- 追加の負担なく可観測性を得られます。 問題が起きたときに、実行ごとのタイムラインを確認できます。
- 結合がありません。 実装(DB、Slack、またはその両方)を変更しても、呼び出し側に手を加える必要がありません。
- デフォルトで非同期です。
waitForSubWorkflow: falseにより、監査ログの記録がメインワークフローを遅らせません。
監査ログのワークフローは、適切なステートフルサブワークフローの例です。副作用こそが目的です。
1.7 ミドルウェアパターン
Webhook ワークフローが API の形をしているなら、API として扱います。サブワークフローはミドルウェアになります。メインハンドラーの前に実行され、処理をそのまま通すか、4xx で早期終了する、小さなステートレス関数です。
Webhook
→ [Verify JWT] # decode + validate; 401 on failure
→ [Rate limit] # check + bump counter; 429 on failure
→ IF (all middleware ok)
→ Main handler logic
→ Respond 200
→ ELSE → Respond with the 4xx the middleware returned
代表的な例は、n8n 内でカスタム JWT 認証を実装することです。Verify JWT(タグ subworkflow)は、生の Authorization ヘッダーを受け取り、デコードして署名と有効期限を検証し、{ ok: true, user_id } または { ok: false, status: 401, message } を返します。呼び出し元は ok を条件に IF を実行し、失敗時は早期に応答し、成功時は処理を続けます。
インラインではなくサブワークフローにする理由は、認証が必要なすべての Webhook で同じものを呼び出せるためです。ライブラリの差し替え、署名キーのローテーション、リフレッシュトークンのロジックの追加を、1 か所で行えます。再利用する対象が明確で、契約が小さく、すべての API エンドポイントで失敗時のレスポンス形式が一貫します。
4xx/5xx のレスポンス形式には n8n-error-handling-official を、基盤となるシークレットの取り扱いには n8n-credentials-and-security-official を組み合わせてください。
2. 繰り返しパターン
以前に作ったことがあるものを、これから作ろうとしています。手を止めて、検索してください。
search_workflows({ query: 'date' })
search_workflows({ tags: ['customer'] })
search_workflows({ tags: ['subworkflow'] })
該当するものがあれば、それを使ってください。なければ、サブワークフローとして作成し、次の検索で見つかるようにタグを付けてください。この方法を機能させるのは、タグの規約(subworkflow、ドメインタグ、tool)です。
ほとんどの処理がサブワークフローにあるなら、長く直線的なワークフローでも問題ありません
サブワークフローの呼び出しと判断による、ほぼ直線的なオーケストレーションであれば、ワークフローにノードが 20 個以上あっても読みやすさを保てます。構成は次のとおりです(監査ログノードは、「実際のステップの合間にある副次的な観察」の鮮明な例としてのみ示しています。ユーザーが監査ログを求めた場合に限り含めてください)。
Webhook
→ Audit log (sub-workflow)
→ Validate
→ Audit log (sub-workflow)
→ IF auth ok
→ Look up user (or sub-workflow)
→ Audit log (sub-workflow)
→ Process step 1 (sub-workflow)
→ Audit log (sub-workflow)
→ Process step 2 (sub-workflow)
→ Audit log (sub-workflow)
→ Decide eligibility (sub-workflow)
→ Audit log (sub-workflow)
→ Send notification (sub-workflow)
→ Respond
各「論理ステップ」は、サブワークフローの呼び出しです。呼び出し元は長くても直線的な流れになり、上から下へ簡単に追えます。ロジックはサブワークフロー内にあります。
これは、20 個のインライン変換を含む 20 ノードのワークフローとは異なります。そのようなワークフローは読みにくくなります。上記のパターンで問題がない理由は次のとおりです。
- 各ノードの目的は 1 つ(特定のサブワークフローの呼び出し)です。
- ノードグループでセクションを示し、付箋で注釈を付けます(
n8n-workflow-lifecycle-officialの「読みやすさ」に従います)。 - セクションを調べるには、呼び出しているサブワークフローを開きます。これがカプセル化です。
- 実装を読まなくても、トップレベルのオーケストレーションロジックを確認できます。
ワークフローにトップレベルのボックスが 7 個を大きく超えていて、Execute Workflow の呼び出しと分岐が大半を占めていない場合は、再利用やテストが必要な箇所をさらに切り出し、残りはインラインのままグループ化してください(ノードグループ)。
切り出さないケース
- ロジックのない単一の HTTP 呼び出し。
Execute Workflow → HTTP Request → returnだけのサブワークフローでは、意味のない境界が増えるだけです。インラインにしてください。 - 呼び出し元固有の構造と密接に結び付いている場合。 チャンクが、この呼び出し元だけが生成する深くネストされた入力を受け取る場合、切り出しても結び付きの場所が移るだけです。まずデータ構造を修正してください。
- パフォーマンスが重要なホットパス。 サブワークフローを呼び出すたびに、わずかですが実際にレイテンシーが増加します。高スループットのワークフローでは、境界を追加する前にプロファイリングしてください。
構築前に検索する手順
ユーザーが複数のステップを含むものや、汎用的に聞こえるものを説明した場合:
1. search_workflows with relevant tags and/or query (e.g. `tags: ['subworkflow']`, a domain tag, the operation keyword)
2. If candidates appear, fetch get_workflow_details on the top 1-3
3. Confirm fit by reading the inputs/outputs and (briefly) the body
4. If a fit exists → use it. Tell the user "I found `<name>`. Using that."
5. If no fit exists → build new and tag it (`subworkflow`, domain, `tool`) so the next search finds it
「ユーザーに伝える」ステップは重要です。ライブラリにすでに何があるかを知ることができます。
見つかるはずのワークフローが表示されない場合、最もよくある原因は、ワークフローごとの MCP アクセスが有効になっていないことです。n8n-workflow-lifecycle-official の references/MCP_ACCESS_PER_WORKFLOW.md を参照してください。
サブワークフローの入出力
サブワークフローは Execute Workflow Trigger ノードによってトリガーされます。トリガーで入力スキーマを宣言します。呼び出し元は Execute Workflow を介してデータを渡し、サブワークフローは最後のノードが出力するものを返します。
明示的なフィールドを指定して、常に「Define Below」を使用する
Execute Workflow Trigger には、2 つの入力モードがあります。デフォルトでは「Define Below」(型付きフィールド)を使用してください。 エージェントツール(fromAi() 経由)や、構造化された呼び出し元から値を渡せるのはこのモードだけです。フィールドを宣言しないと、エージェントが値を入力するためのスキーマがなく、サブワークフローを toolWorkflow として適切に接続できません。
形式:
const subTrigger = trigger({
type: 'n8n-nodes-base.executeWorkflowTrigger',
config: {
parameters: {
workflowInputs: {
values: [
{ name: 'list_of_ids', type: 'array' },
{ name: 'include_transcript', type: 'boolean' },
{ name: 'session_id', type: 'string' },
],
},
},
},
})
宣言した各入力は、呼び出し元が値を入力できる型付きパラメーターになります。ワークフロー内では、$json.list_of_ids などでアクセスするか、下流の任意の場所から $('When Executed by Another Workflow').first().json.<field> でアクセスします。
型(string、number、boolean、array、object)は慎重に選んでください。エージェントツールのパラメーターを入力する際、モデルはこれらを必須の型として使用し、呼び出し元を接続する際には人間がこれらを頼りにします。
例外 1:バイナリデータにはパススルーモードを使用する
サブワークフローでバイナリデータ(画像、ファイル、PDF)を受け取る必要がある場合、型付きフィールドは JSON のみを対象とするため、「Define Below」は機能しません。パススルーに切り替えてください。
const subTrigger = trigger({
type: 'n8n-nodes-base.executeWorkflowTrigger',
config: {
parameters: {
inputSource: 'passthrough',
},
},
})
パススルーモードでは、サブワークフローは呼び出し元のアイテムを binary スロットも含めてそのまま受け取ります。代償として、型付きの入力スキーマがないため、エージェントツールは fromAi() 経由でパラメーターを渡せません。バイナリデータを渡す必要があり、エージェントではなく別のワークフローから呼び出されるサブワークフローには、このモードを使用してください。
バイナリデータが必要で、かつエージェントから呼び出されるサブワークフローについては、n8n-binary-and-data-official の references/AGENT_TOOL_BINARY.md を参照してください(エージェントツールはバイナリデータを直接渡せません)。
例外 2:入力のないサブワークフローにはパススルーを使用する
「Define Below」では、少なくとも 1 つのフィールドを宣言する必要があります。実際に入力を受け取らないサブワークフロー(「アクティブな認証情報を一覧表示する」ツール、「現在の件数」を調べる処理、引数のない操作など)では、空のスキーマを設定する場所がないため、パススルーが唯一の選択肢です。
入力がない場合に限ってパススルーを使用する場合:
- 本文の先頭に、フィールドを設定せず、「Keep Only Set」モードにした
Set(Edit Fields)ノードを配置してください。 これにより呼び出し元の JSON がクリアされ、下流のノードが呼び出し元から渡されたデータの形に左右されて、意図せずフィールドを読み取ることを防げます。このノードがないと、本文は呼び出し元から転送されたデータをそのまま引き継いでしまいます。 - 入力が想定されていないことを説明する付箋をトリガーに追加してください。 後から読む人(およびこれをツールとして再接続するエージェント)が、パススルーを使っているのはバイナリデータのためではなく、設計上スキーマが空だからだと理解できるようにする必要があります。
入力がない場合でも、エージェントツールとの接続は機能します。toolWorkflow は、入力マッピングにフィールドがないサブワークフローを受け入れます。エージェントが判断するのは、呼び出すかどうかだけです。n8n-ai-nodes-official の references/TOOLS.md にあるパターン(「fromAi パラメーターが 0 個」)をそのまま適用できます。
その他の規約
-
ワークフローの
descriptionに入力と出力を記載します。 フィールド名、型、用途を記載してください。呼び出し元(人間やエージェント)が契約を確認する際に読むのが、この説明です。 -
一貫した形式で返します。 想定される失敗(例:解析エラー)では、例外をスローするのではなく、
{ success: false, error: '...' }を返します。呼び出し元はエラー出力をラップせずに分岐できます。 -
呼び出し元ができたら、入力スキーマを契約として扱います。 任意フィールドの追加は安全です。フィールド名の変更や削除も可能ですが、慎重に行ってください。すべての呼び出し元(サブワークフローの名前を指定した
search_workflowsと手動スキャン)を洗い出し、同じ変更で移行し、公開前にvalidate_workflowとget_workflow_detailsで検証します。n8n は認識されない入力フィールドでもエラーを出さないため、ここでのサイレントな破損は検出が困難です。サブワークフローにはundefinedが渡され、呼び出し元はそのことに気づきません。 -
最後に Set / Edit Fields ノードを使って戻り値の形式を整えます。 これは任意ですが、最後の計算ノードに不要なフィールドが含まれている場合は必要になることがあり、サブワークフローでは必須でない場合でも推奨される方法です。境界で戻り値の契約を明示するため、読者は 1 つのノードを確認するだけで API を把握できます。これは
n8n-expressions-officialの Set ノードのアンチパターンに対する正当な例外です。サブワークフローの最後のノードを暗黙的に利用するのは、すべての呼び出し元です。そのため、Set ノードを明示的な API 境界として設ける意義があります。ノード名はReturnまたはReturn <thing>にします。 -
ストレージ形式ではなく、自然な形式で返します。 Data Table、S3 内のファイル、その他のストレージレイヤーを持つサブワークフローでは、その表現形式を呼び出し元に見せないようにします。基盤となるストレージが JSON 文字列化されたテキストや別の内部形式であっても、配列は配列として、オブジェクトはオブジェクトとして、日付は ISO 文字列として返します。戻り値の契約が インターフェース です。ストレージのレイアウトは 実装の詳細 です。
よくある失敗:サブワークフローに「新規」パス(生成したばかりのデータで、自然な形式)と「キャッシュ」パス(
_object列から読み込んだデータで、まだ文字列化されたまま)がある場合です。誤った考え方は、「形式を合わせる」ために新規パスを文字列化することです。正しい考え方は、キャッシュパスを解析して、どちらも自然な形式で返すことです。呼び出し元がどちらのデータを受け取ったかを知る必要はありません。
エージェントツールとして接続するサブワークフローについては、n8n-ai-nodes-official の references/SUBWORKFLOW_AS_TOOL.md(AI Agent ノード)、または n8n-agents-official の references/TOOLS.md(ファーストクラスの n8n Agent)を参照してください。ファーストクラスの Agent のワークフローツールは、Agent と同じプロジェクト内にあり、公開済みである必要があります。また、その fixed / expression 入力から呼び出し元のトリガーデータを読み取ることはできません。
サブワークフローの呼び出し:Execute Workflow のモード
呼び出し元の Execute Workflow ノードには、inputs/workflowId 以外に次の 2 つの設定があります。
modeのデフォルトは'all'です。サブワークフローは、N 個すべてのアイテムを入力として 1 回実行されます。他のワークフローと同様に、アイテムはノードをアイテムごとに通過します。サブワークフローを N 回に分けて、1 回の実行につき 1 アイテムずつ処理するには、mode: 'each'を設定します。サブワークフローの本体が通常どおりアイテムを処理するだけなら、両者は同じ動作になります。違いが重要になるのは、サブワークフローの本体がアイテムをちょうど 1 つ受け取ることを前提としている場合です(実行ごとの集計、「操作対象はこの顧客」とするロジック、入力ごとに 1 回だけ実行すべき最後の書き込みなど)。mode: 'each'はこの前提に合致しますが、mode: 'all'では前提が崩れます。アイテムごとの反復処理が必要な場合は、サブワークフロー内に Loop Over Items ノードを置くより、mode: 'each'を優先してください。waitForSubWorkflowのデフォルトはtrueです。options.waitForSubWorkflow: falseを設定すると、呼び出しを開始してすぐに処理が先へ進み、サブワークフローはバックグラウンドで続行されます。呼び出し元の下流ノードには戻りデータが渡されません。
mode: 'each' と waitForSubWorkflow: false の組み合わせは、n8n が提供する 唯一の真の並列化です。N 個のサブワークフロー実行が待機なしでディスパッチされ、並行して実行されます(ただし、インスタンスごとの同時実行数の上限と、呼び出しごとのオーバーヘッドの制約を受けます)。「独立したジョブを N 個開始し、後でポーリング/集計する」場合に役立ちます。たとえば、アイテムごとに時間のかかるジョブをディスパッチし、それぞれを Data Table で追跡して、すべての行が完了を示すか、タイムアウトするまでループします。
実行を開始して応答を待たず、後からポーリングするパターンについては、references/SUBWORKFLOW_PATTERNS.md の「Fire-and-forget parallelization」を参照してください。
参照ファイル
| ファイル | 読むタイミング |
|---|---|
references/SUBWORKFLOW_PATTERNS.md | mode: 'all' と 'each' の違いとデフォルト、入力の形状による分割(binary/passthrough と Define Below)、Data Table のポーリングを使った実行開始後に待機しない並列化 |
references/NAMING_AND_DISCOVERY.md | 新しいサブワークフローの命名とタグ付け、既存のサブワークフローの検索、タグの規則 |
アンチパターン
| アンチパターン | 発生する問題 | 修正方法 |
|---|---|---|
| 同じ日付解析ノードを3つのワークフローに重複して作成する | バグ修正が2か所だけに適用され、3つ目で漏れます | subworkflow タグを付けた Parse <format> date サブワークフローを1つ作成し、処理を集約します |
| 検索せずに新しいサブワークフローを作成する | ライブラリに重複が増え、今後の検索で両方見つかります | まず必ず search_workflows を実行します |
| 純粋な処理に見える名前や説明のサブワークフローが、ひそかにログテーブルへ書き込む | 呼び出し側が再試行や冪等性を判断できず、予期しない副作用に遭遇します | 副作用を契約の一部にする(名前を変更し、説明に明記して、その結果を返す)か、処理を切り離します |
description がないサブワークフロー | 今後の検索で見つからず、誰も何をするのかわかりません | 入力・出力の形式と目的を含む description を設定します |
Helper 3 という名前のサブワークフロー | 名前から何をするのかわかりません | 動詞から始まる説明的な名前(Parse RFC2822 date)を付けます。n8n-workflow-lifecycle-official の NAMING_CONVENTIONS.md を参照してください |
| タグのないサブワークフロー | tags フィルターに表示されず、後で探せなくなります | 作成直後に update_workflow の addTags を使ってタグ(subworkflow、ドメイン、tool)を付けます |
バイナリを扱わず、入力を意図的にゼロにしているわけでもないのに、Execute Workflow Trigger が passthrough に設定されている | 型付きスキーマがないため、エージェントツールが fromAi 経由でパラメーターを設定できず、構造化された呼び出し側も値を適切に渡せません | 宣言した workflowInputs.values(各フィールドの名前と型)を使って「Define Below」を選択します。例外は、バイナリを受け取るサブワークフローと、本当に入力を受け取らないサブワークフローです(「Exception 2」を参照) |
| 入力ゼロのサブワークフローで、Set-to-clear ノードと説明用の付箋を使わずに passthrough トリガーを使用する | 本文が呼び出し側から渡された無関係なフィールドを暗黙に読み込み、後から読む人は passthrough がバイナリ用だと思い込みます | 本文の先頭に Set(「Keep Only Set」、フィールドなし)を追加し、トリガーに入力が不要であることを示す付箋を追加します |
| バイナリ入力を必要とするサブワークフローをエージェントツールとして呼び出す | エージェントツールはバイナリを直接渡せません | 適切なパターンについては、n8n-binary-and-data-official の AGENT_TOOL_BINARY.md を参照してください |
| 処理の切り出しがない30ノードのワークフロー | 読みにくく、テストしにくく、置き換えも困難です | 論理的なセクションをサブワークフローに切り出します |