Contents
1. Cloudflare Workers API の概要と Node.js ランタイム
Cloudflare Workers は V8 isolates 上で動作するサーバーレスプラットフォームですが、2026 年リリースの Node.js ランタイム によって、従来の Service Worker API だけでなく標準的な http モジュールがそのまま利用可能になりました。これにより既存の Node.js エコシステム(ミドルウェアやフレームワーク)をエッジへ移行しやすくなります。
1‑1. 最新アップデート概観
2024 年以降に追加された主な機能は以下の通りです。各項目は Cloudflare の公式リリースノートまたは開発者ドキュメントに基づいています【1】。
- モジュラー型 API:
@cloudflare/workers-typesが標準化され、TypeScript での型安全が向上。 - Durable Objects v2:内部ロックが最適化され、同時書き込みスループットが約 30 % 向上(ベンチマークは公式ブログに掲載)。
- Workers Insights:リアルタイムメトリクス API が統合され、
console.logの出力先をカスタマイズ可能。 - Cache‑Control 拡張:
stale‑while‑revalidateなど標準ヘッダーのサポートが強化された。一方、edge-max-ageヘッダーは現在公式ドキュメントに記載がなく、実装時は従来通りCache-Controlを利用してください【2】。
1‑2. Node.js ランタイムでの HTTP ハンドラ実装ポイント
Node.js ランタイム上では 標準の http.createServer がそのまま動作し、リクエストは IncomingMessage、レスポンスは ServerResponse のインスタンスとして提供されます。以下に実装時の留意点をまとめました。
- エントリポイントはプロジェクトルートの
src/index.js(または.ts)に配置し、wrangler publishでデプロイ可能。 - ミドルウェア互換性:
helmet,corsなどの Express 系ミドルウェアは問題なく使用できるが、一部 Node のコアモジュール(例:fs)は利用不可です。 - エッジキャッシュ制御は
Cache-Controlヘッダーで行い、stale‑while‑revalidateと組み合わせてエッジ側の再取得タイミングを調整します。 - リソース上限:Workers のデフォルトは CPU 時間 50 ms、メモリ 128 MB(※従来の「デフォルトタイムアウト」や「メモリ上限」と呼ばれることがあります)【3】。これを超える処理は自動的に中断されるため、非同期処理は必ず
awaitまたはストリームで実装してください。
実装例(Node.js HTTP サーバー)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// src/index.js import http from 'node:http'; // 簡易 JSON API のエントリポイント const server = http.createServer(async (req, res) => { // CORS 設定はヘッダーで一括対応 res.setHeader('Access-Control-Allow-Origin', '*'); if (req.method === 'GET' && req.url === '/status') { res.writeHead(200, { 'Content-Type': 'application/json', // エッジ側キャッシュの指示(公式ヘッダーのみ使用) 'Cache-Control': 'public, max-age=60, stale-while-revalidate=300' }); res.end(JSON.stringify({ ok: true, ts: Date.now() })); } else { res.writeHead(404); res.end('Not Found'); } }); // Workers が期待するエクスポート形式 export default { fetch: server }; |
2. 代表的な業務パターンと実装サンプル
以下では、実際に Cloudflare Workers を導入した企業で頻出した 5 つのユースケース を取り上げ、コード例とポイントを解説します。すべて Node.js ランタイムで動作することが前提です。
2‑1. メール自動化
メール送信はバックエンド不要で完結できるため、サーバーレスの典型的な活用例です。ここでは SendGrid API を呼び出すシンプルな実装を示します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
export async function onRequestPost({ request, env }) { const { email, name } = await request.json(); const payload = { personalizations: [{ to: [{ email }], subject: 'ご登録ありがとうございます' }], from: { email: 'noreply@example.com', name: 'Example Corp' }, content: [{ type: 'text/plain', value: `こんにちは ${name} 様、` }] }; try { const resp = await fetch('https://api.sendgrid.com/v3/mail/send', { method: 'POST', headers: { Authorization: `Bearer ${env.SENDGRID_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!resp.ok) throw new Error(`SendGrid error ${resp.status}`); return new Response('メール送信完了', { status: 200 }); } catch (e) { console.error(e); return new Response('メール送信失敗', { status: 500 }); } } |
ポイント
- 環境変数は wrangler.toml の [vars] に登録し、コード内で env.XXXX として安全に参照。
- エラーハンドリングは Workers の標準的な try / catch で行い、失敗時はステータスコード 500 を返す。
2‑2. フォーム送信処理
Cloudflare Forms と Workers を組み合わせると、サーバーレスかつスパム対策済みのフォームバックエンドが構築できます。バリデーションには軽量スキーマライブラリ zod を使用します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { z } from 'zod'; const schema = z.object({ name: z.string().min(1, '名前は必須です'), email: z.string().email('有効なメールアドレスを入力してください'), message: z.string().min(10, 'メッセージは最低10文字') }); export async function onRequestPost({ request, env }) { const data = await request.json(); const result = schema.safeParse(data); if (!result.success) return new Response('Invalid input', { status: 400 }); // 任意で KV に保存 await env.CONTACTS_KV.put(`msg-${Date.now()}`, JSON.stringify(result.data)); return new Response('送信完了', { status: 200 }); } |
ポイント
- Forms 設定は Cloudflare ダッシュボードの「Form Submissions」から有効化し、Webhook URL に Workers のエンドポイントを指定。
- バリデーション失敗時は 400 を返すことでフロント側に即座にフィードバック。
2‑3. 外部 API 連携(GraphQL / REST)
エッジから外部サービスへ直接リクエストすることで、オリジンへの往復遅延を削減できます。以下は GraphQL エンドポイントへの問い合わせ例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
export async function onRequest({ request, env }) { const query = ` query GetProduct($id: ID!) { product(id: $id) { name price } }`; const variables = { id: '12345' }; const resp = await fetch('https://api.example.com/graphql', { method: 'POST', headers: { Authorization: `Bearer ${env.EXTERNAL_API_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables }) }); const json = await resp.json(); return new Response(JSON.stringify(json), { status: 200 }); } |
ポイント
- 外部 API の認証情報は必ず環境変数で管理し、コードにハードコーディングしない。
- fetch はエッジロケーションから直接行われるため、レスポンスヘッダーの cf-ray で実測レイテンシを確認可能。
2‑4. 高度キャッシュ戦略
Cache‑Control ヘッダーを駆使してエッジ側のキャッシュ動作を細かく制御します。公式ドキュメントに edge-max-age は未掲載 であるため、ここでは標準的な指示子のみ使用しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
export async function onRequest({ request, env }) { const cache = caches.default; let response = await cache.match(request); if (!response) { // オリジン取得 const originResp = await fetch(`https://origin.example.com${new URL(request.url).pathname}`); // キャッシュヘッダーを付与 response = new Response(originResp.body, originResp); response.headers.set('Cache-Control', 'public, max-age=60, stale-while-revalidate=300'); await cache.put(request, response.clone()); } return response; } |
ポイント
- stale‑while‑revalidate により、キャッシュが期限切れでもバックグラウンドで再取得を開始し、ユーザー体感速度を向上。
- 必要に応じて Cache-Control: no-store で特定リクエストのキャッシュ除外も可能。
2‑5. 認証・認可フロー
JWT と OAuth2 の両方に対応したミドルウェア的実装例です。@tsndr/cloudflare-worker-jwt は Workers 向けに最適化された軽量パッケージです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { verify } from '@tsndr/cloudflare-worker-jwt'; export async function onRequest({ request, env }) { const auth = request.headers.get('Authorization'); if (!auth?.startsWith('Bearer ')) return new Response('Unauthorized', { status: 401 }); const token = auth.slice(7); try { const payload = await verify(token, env.JWT_PUBLIC_KEY, { algorithm: 'RS256' }); // スコープチェック例 if (!payload.scopes?.includes('read:data')) throw new Error('Insufficient scope'); return new Response(JSON.stringify({ user: payload.sub }), { status: 200 }); } catch (e) { console.error(e); return new Response('Invalid token', { status: 403 }); } } |
ポイント
- 公開鍵は wrangler.toml の [vars] に Base64 エンコードして格納し、環境変数経由で取得。
- 必要に応じてトークンの有効期限 (exp) を検証し、リフレッシュロジックを別エンドポイントで実装すると安全性が向上。
3. KV と Durable Objects の組み合わせ例
KV は永続ストレージ、Durable Objects(DO)は低レイテンシなインメモリ状態管理に適しています。両者を併用することで「リアルタイム集計+永続化」の典型的なステートフルパターンが実現できます。
3‑1. シナリオと設計ポイント
- 目的:訪問者ごとのページビュー数をエッジで即時カウントし、一定時間ごとに KV にバッチ書き込みして永続化。
- DO の役割:インスタンス単位でメモリ上に
countを保持し、同時書き込みは DO がシリアライズ的に処理するため競合が起きにくい。 - KV の役割:サーバーダウンや再デプロイ時の状態復元、長期分析用の永続保存。
3‑2. Durable Object 本体(TypeScript)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// src/counter.do.ts export class Counter { private count = 0; private timer?: number; constructor(private state: DurableObjectState, private env: Env) { // 起動時に KV から過去のカウントを復元 this.state.blockConcurrencyWhile(async () => { const stored = await this.env.VIEW_KV.get(this.id.toString()); this.count = stored ? Number(stored) : 0; }); this.startFlushTimer(); } // HTTP リクエストで呼び出される入口 async fetch(request: Request): Promise<Response> { this.count++; return new Response(`Count=${this.count}`, { status: 200 }); } // 30 秒ごとに KV に永続化するタイマー private startFlushTimer() { this.timer = setInterval(async () => { await this.env.VIEW_KV.put(this.id.toString(), String(this.count)); }, 30_000); } } |
3‑3. エンドポイント側から DO を呼び出す(JavaScript)
|
1 2 3 4 5 6 |
export async function onRequest({ request, env }) { const id = env.COUNTER.idFromName('global'); const obj = env.COUNTER.get(id); return await obj.fetch(request); } |
実装上の留意点
- state.blockConcurrencyWhile によって KV 読み込み中は同時リクエストをブロックし、初期化レースコンディションを防止。
- タイマーは Workers の制限(最大 30 秒)以内で完了するように設計し、長時間実行は setTimeout に委譲しない。
4. ローカル開発環境とデバッグ手法
ローカルでのエミュレーションは本番相当の挙動を確認できる重要なステップです。ここでは wrangler のセットアップから VS Code デバッガ連携まで順序立てて解説します。
4‑1. Wrangler のインストールと基本設定
- Node.js v20 以上と npm をインストール
- グローバルに
wranglerを導入
|
1 2 |
npm install -g @cloudflare/wrangler |
- プロジェクトを初期化し、Node.js ランタイムを有効化
|
1 2 3 |
mkdir my-worker && cd my-worker wrangler init --site # サイトテンプレートで作成 |
wrangler.tomlに必要なバインディングとランタイム指定を書き込む(抜粋)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
name = "my-worker" compatibility_date = "2026-05-01" main = "./src/index.js" # Node.js ランタイムの有効化 [vars] SENDGRID_API_KEY = "$SENDGRID_API_KEY" EXTERNAL_API_TOKEN = "$EXTERNAL_API_TOKEN" [[kv_namespaces]] binding = "CONTACTS_KV" id = "xxxxxxxxxxxxxxx" [[durable_objects]] name = "COUNTER" class_name = "Counter" |
4‑2. ローカル KV / DO のエミュレーション
wrangler devは メモリ上で KV と DO を自動的にエミュレートします。永続化が必要な場合はwrangler kv:bulk import data.jsonでローカル JSON データをロードできます。- エミュレーション実行例
|
1 2 |
wrangler dev --local # ローカルモードで起動 |
起動後は http://127.0.0.1:8787/ にアクセスし、ブラウザや curl からリクエストを送信できます。
4‑3. VS Code デバッガとの連携
- デバッグポートの公開
bash
wrangler dev --inspect=9229 .vscode/launch.jsonにattach構成を追加
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "attach", "name": "Attach to Wrangler", "port": 9229, "restart": true, "localRoot": "${workspaceFolder}", "remoteRoot": "/" } ] } |
- VS Code の「実行とデバッグ」から Attach to Wrangler を選択し、ブレークポイントを設定すればコードステップや変数確認が可能です。CPU 時間・メモリ上限はローカルでもシミュレーションされるため、本番環境でのタイムアウト検知に有効です。
5. 導入効果と定量的ベネフィット(実証データ)
Cloudflare が公開した 22 社・サイトのケーススタディ を元に、Workers 移行後のコスト削減率とパフォーマンス向上率をまとめました。すべての数値は Cloudflare の公式レポート【4】および各社が提供した内部データから算出しています。
5‑1. コスト削減の内訳
| 項目 | 従来方式(例:EC2 + CDN) | Workers 移行後 | 削減率 |
|---|---|---|---|
| コンピューティング料金 | $120 / 月 (t3.small x 2) | $35 / 月 (リクエスト課金) | 71 % |
| データ転送費用 | $45 / 月 | $12 / 月 (エッジローカリティで削減) | 73 % |
| オートスケール運用コスト | 手動監視ツール $30 / 月 | 無料(Workers が自動) | 100 % |
合計で 月額約 $120 → $35 に低減し、年間で約 $1,020 の削減 が見込めます。
5‑2. パフォーマンス改善ポイント
- エッジローカリティ:ユーザーの最寄りデータセンターでコードが実行されるため、平均 RTT が 45 ms → 31 ms に短縮(約 30 % 改善)。測定は Cloudflare Analytics の
cf-rayヘッダーから取得【5】。 - キャッシュ最適化:
stale‑while‑revalidateと標準Cache-Controlの組み合わせで、オリジンへのリクエスト回数が 58 % 減少。結果としてバックエンド負荷が軽減し、スケーラビリティが向上しました。 - Cold Start 時間:Node.js ランタイムは事前ウォームアップ機能により、最初のリクエスト応答が <10 ms に抑えられたケースが多数報告されています。
5‑3. ROI 推定例(中小企業 A 社)
| 指標 | 移行前 (年) | 移行後 (年) | 差分 |
|---|---|---|---|
| インフラ費用 | $1,440 | $420 | -$1,020 |
| 平均ページロード時間 | 2.8 s | 2.0 s | -28 % |
| コンバージョン率(推定) | 3.5 % | 4.2 % | +20 % |
上記は単純化したシミュレーションですが、コスト削減 + ユーザー体感速度向上 が売上増加に直結することを示しています。
おわりに
本ガイドでは 2026 年版 Cloudflare Workers の Node.js ランタイム を軸に、最新機能・実装パターン・開発フロー・導入効果まで一貫して解説しました。以下のステップで移行を進めることを推奨します。
wrangler initでローカル環境を構築し、サンプルコードを動作確認- 現行システムの API エンドポイントを Node.js HTTP ハンドラに置き換え、ミドルウェア互換性を検証
- キャッシュ戦略と KV/DO の組み合わせでステートフル要件を実装
- 本番デプロイ前に wrangler dev --inspect で負荷・タイムアウトテストを実施
- 移行後は Cloudflare Insights と自社モニタリングで KPI(コスト、レイテンシ)を継続的に測定
これらの手順を踏むことで、エッジファーストアーキテクチャへのスムーズな移行と、コスト削減・パフォーマンス向上という実証済みベネフィットを最大化できます。
参考文献
- Cloudflare Developers Blog, “Introducing Durable Objects v2”, 2025‑11‑03.
- Cloudflare Docs, Cache Control (2026‑04‑01). (
edge-max-ageは記載なし) - Cloudflare Workers Runtime Limits, official documentation, accessed 2026‑05‑20.
- Cloudflare Case Studies – 22 Companies Using Workers, 2026‑03‑15.
- Cloudflare Analytics – RTT measurement methodology, 2026‑02‑28.