n8n-patterns について
n8n-patternsは、n8nで自動化ワークフローを構築する人向けの実践ガイドです。トリガー、データ処理、エラー対応、再利用可能なサブワークフロー、デプロイのパターンを扱います。
主な機能
- 01Webhook・スケジュール・アプリのトリガー
- 02データ変換と制御フロー
- 03エラー処理とリトライのパターン
- 04サブワークフローとREST API呼び出し
- 05認証情報管理とセルフホスト設定
活用シーン
- 01イベント駆動または定期実行の設計
- 02APIページネーションとデータ変換
- 03ワークフローへのエラー処理とリトライ追加
- 04再利用可能なサブワークフローの設計
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mindmorass/ reflex --skill n8n-patternsインストール後、Claude Code で/n8n-patternsを入力して読み込まれたか確認します。
詳細
n8n ワークフローパターン
オープンソースのワークフロー自動化ツールである n8n を使って、堅牢なワークフロー自動化を構築しましょう。
概要
n8n は、アプリやサービスを連携するセルフホスト可能なワークフロー自動化プラットフォームです。主な機能:
- 400 以上の連携機能を備えたビジュアルワークフロービルダー
- セルフホストまたはクラウドへのデプロイ
- カスタムロジック用のコードノード(JavaScript/Python)
- リアルタイム自動化のための Webhook トリガー
- モジュール設計のためのサブワークフロー
コアコンセプト
ワークフローの構造
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Trigger │───▶│ Node │───▶│ Output │
│ (Start) │ │ (Process) │ │ (Action) │
└─────────────┘ └─────────────┘ └─────────────┘
ノードの種類
| 種類 | 目的 | 例 |
|---|---|---|
| トリガー | ワークフローを開始 | Webhook、スケジュール、アプリトリガー |
| アクション | 操作を実行 | HTTP Request、データベース、メール |
| 変換 | データを変更 | Set、Code、IF、Switch |
| フロー | 実行を制御 | Merge、Split、Wait、Loop |
トリガーパターン
Webhook トリガー
{
"nodes": [
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "my-webhook",
"responseMode": "responseNode",
"options": {
"rawBody": true
}
}
}
]
}
ベストプラクティス:
- カスタム応答には
responseNodeを使用します - 署名の検証には
rawBodyを有効にします - 認証を追加します(Header Auth、Basic Auth)
スケジュールトリガー
{
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * 1-5"
}
]
}
}
}
一般的なスケジュール:
0 * * * *- 毎時0 9 * * 1-5- 平日の午前 9 時0 0 * * 0- 毎週日曜日の午前 0 時*/15 * * * *- 15 分ごと
アプリトリガー(ポーリング)
{
"name": "GitHub Trigger",
"type": "n8n-nodes-base.githubTrigger",
"parameters": {
"owner": "{{$env.GITHUB_OWNER}}",
"repository": "{{$env.GITHUB_REPO}}",
"events": ["issues", "pull_request"]
}
}
データ変換パターン
Set ノード(データを変換)
{
"name": "Transform Data",
"type": "n8n-nodes-base.set",
"parameters": {
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{
"name": "fullName",
"value": "={{ $json.firstName }} {{ $json.lastName }}",
"type": "string"
},
{
"name": "timestamp",
"value": "={{ DateTime.now().toISO() }}",
"type": "string"
}
]
}
}
}
Code ノード(JavaScript)
// Process items with custom logic
const results = [];
for (const item of $input.all()) {
const data = item.json;
// Transform data
results.push({
json: {
id: data.id,
processed: true,
score: calculateScore(data),
timestamp: new Date().toISOString()
}
});
}
function calculateScore(data) {
return data.value * 0.8 + data.bonus * 0.2;
}
return results;
Code ノード(Python)
# Enable Python in n8n settings
import json
from datetime import datetime
results = []
for item in _input.all():
data = item.json
# Transform data
results.append({
"json": {
"id": data.get("id"),
"processed": True,
"timestamp": datetime.now().isoformat()
}
})
return results
制御フローパターン
IF ノード(条件分岐)
{
"name": "Check Status",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.status }}",
"rightValue": "active",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
}
}
}
Switch ノード(複数分岐)
{
"name": "Route by Type",
"type": "n8n-nodes-base.switch",
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"outputKey": "order",
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.type }}",
"rightValue": "order",
"operator": { "type": "string", "operation": "equals" }
}
]
}
},
{
"outputKey": "refund",
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.type }}",
"rightValue": "refund",
"operator": { "type": "string", "operation": "equals" }
}
]
}
}
]
},
"fallbackOutput": "extra"
}
}
アイテムをループ
{
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"parameters": {
"batchSize": 10,
"options": {
"reset": false
}
}
}
Merge ノード(データを結合)
{
"name": "Merge Results",
"type": "n8n-nodes-base.merge",
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "userId"
}
]
},
"options": {}
}
}
エラー処理パターン
Error Trigger を使った Try/Catch
{
"nodes": [
{
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"parameters": {}
},
{
"name": "Send Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#alerts",
"text": "Workflow failed: {{ $json.workflow.name }}\nError: {{ $json.execution.error.message }}"
}
}
]
}
失敗時に再試行
{
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.example.com/data",
"options": {}
},
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000
}
Stop and Error ノード
{
"name": "Validation Failed",
"type": "n8n-nodes-base.stopAndError",
"parameters": {
"errorMessage": "Invalid input: {{ $json.error }}"
}
}
サブワークフローパターン
Execute Workflow ノード
{
"name": "Process Order",
"type": "n8n-nodes-base.executeWorkflow",
"parameters": {
"source": "database",
"workflowId": "order-processing-workflow-id",
"mode": "each",
"options": {
"waitForSubWorkflow": true
}
}
}
ベストプラクティス:
- 再利用可能なロジックにはサブワークフローを使用します
- ワークフロー間で渡すデータは最小限にします
- 必要に応じて
waitForSubWorkflowを設定します - 整理にはワークフロータグを使用します
HTTP Request パターン
REST API 呼び出し
{
"name": "API Request",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.example.com/v1/resource",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "data",
"value": "={{ JSON.stringify($json) }}"
}
]
},
"options": {
"timeout": 30000,
"response": {
"response": {
"fullResponse": false,
"responseFormat": "json"
}
}
}
}
}
ページネーションパターン
// Code node for API pagination
const allResults = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await this.helpers.httpRequest({
method: 'GET',
url: `https://api.example.com/items?page=${page}&limit=100`,
headers: {
'Authorization': `Bearer ${$env.API_TOKEN}`
}
});
allResults.push(...response.data);
hasMore = response.hasNextPage;
page++;
// Rate limiting
await new Promise(r => setTimeout(r, 100));
}
return allResults.map(item => ({ json: item }));
認証情報の管理
環境変数
// Access in expressions
{{ $env.API_KEY }}
{{ $env.DATABASE_URL }}
// Access in Code node
const apiKey = $env.API_KEY;
認証情報の種類
| 種類 | 用途 |
|---|---|
httpBasicAuth | Basic 認証 |
httpHeaderAuth | ヘッダー内の API キー |
oAuth2Api | OAuth 2.0 フロー |
httpQueryAuth | クエリ文字列内の API キー |
セルフホスティングパターン
Docker Compose
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://${N8N_HOST}/
- GENERIC_TIMEZONE=UTC
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
postgres:
image: postgres:15
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
n8n_data:
postgres_data:
環境変数(.env)
# n8n Configuration
N8N_HOST=n8n.example.com
N8N_USER=admin
N8N_PASSWORD=secure-password-here
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
# Database
POSTGRES_USER=n8n
POSTGRES_PASSWORD=secure-db-password
# Optional: Queue mode for scaling
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
キューモード(スケーリング)
# docker-compose.queue.yml
services:
n8n:
environment:
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_HEALTH_CHECK_ACTIVE=true
n8n-worker:
image: n8nio/n8n:latest
command: worker
environment:
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
deploy:
replicas: 3
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
一般的なワークフローテンプレート
Webhook からデータベースへ
{
"name": "Webhook to Database",
"nodes": [
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "ingest",
"responseMode": "responseNode"
}
},
{
"name": "Validate",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.id }}",
"rightValue": "",
"operator": { "type": "string", "operation": "notEmpty" }
}
]
}
}
},
{
"name": "Insert",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "insert",
"table": "events",
"columns": "id,type,data,created_at"
}
},
{
"name": "Success Response",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"respondWith": "json",
"responseBody": "={{ { \"success\": true, \"id\": $json.id } }}"
}
}
]
}
スケジュールされた同期
{
"name": "Daily Data Sync",
"nodes": [
{
"name": "Schedule",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [{ "field": "cronExpression", "expression": "0 2 * * *" }]
}
}
},
{
"name": "Fetch Source",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.source.com/data",
"authentication": "predefinedCredentialType"
}
},
{
"name": "Transform",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "return $input.all().map(item => ({ json: { ...item.json, synced_at: new Date().toISOString() } }));"
}
},
{
"name": "Upsert Destination",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "upsert",
"table": "synced_data"
}
}
]
}
イベント駆動型通知
{
"name": "Alert Pipeline",
"nodes": [
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": { "path": "alert" }
},
{
"name": "Route by Severity",
"type": "n8n-nodes-base.switch",
"parameters": {
"rules": {
"values": [
{ "outputKey": "critical", "conditions": { "conditions": [{ "leftValue": "={{ $json.severity }}", "rightValue": "critical" }] } },
{ "outputKey": "warning", "conditions": { "conditions": [{ "leftValue": "={{ $json.severity }}", "rightValue": "warning" }] } }
]
}
}
},
{
"name": "Page On-Call",
"type": "n8n-nodes-base.pagerDuty"
},
{
"name": "Slack Alert",
"type": "n8n-nodes-base.slack"
}
]
}
式のチートシート
| 式 | 説明 |
|---|---|
{{ $json.field }} | 現在のアイテムからフィールドにアクセス |
{{ $json["field-name"] }} | 特殊文字を含むフィールドにアクセス |
{{ $('NodeName').item.json.field }} | 特定のノードのデータにアクセス |
{{ $input.first().json }} | 最初の入力アイテム |
{{ $input.all() }} | すべての入力アイテム |
{{ $env.VAR_NAME }} | 環境変数 |
{{ $now }} | 現在の日時 |
{{ $today }} | 今日の日付 |
{{ $runIndex }} | 現在の実行ランインデックス |
{{ $itemIndex }} | 現在のアイテムインデックス |
{{ $workflow.id }} | ワークフロー ID |
{{ $execution.id }} | 実行 ID |
Luxon DateTime の例
// n8n uses Luxon for dates
{{ $now.toISO() }} // ISO format
{{ $now.toFormat('yyyy-MM-dd') }} // Custom format
{{ $now.plus({ days: 7 }).toISO() }} // Add 7 days
{{ $now.startOf('month').toISO() }} // Start of month
{{ DateTime.fromISO($json.date) }} // Parse ISO string
ベストプラクティス
- 命名:動詞+名詞を使った説明的なノード名を付けます
- エラー処理:必ずエラーワークフローを追加します
- 認証情報:シークレットをハードコードしないでください
- バッチ処理:大規模なデータセットには
splitInBatchesを使用します - タイムアウト:HTTP ノードには適切なタイムアウトを設定します
- ログ記録:デバッグには Code ノードで
console.logを使用します - テスト:有効化する前に手動実行します
- バージョン管理:ワークフローを JSON として git にエクスポートします
- ドキュメント:複雑なロジックには付箋を追加します
- モジュール設計:再利用性を高めるためにサブワークフローを使用します
デバッグのヒント
// In Code node - log to n8n console
console.log('Debug:', JSON.stringify($json, null, 2));
// Return debug info
return [{
json: {
debug: true,
input: $json,
env: $env.NODE_ENV,
timestamp: new Date().toISOString()
}
}];
Resources
コメント
Markdown 対応