CloudflareはPagesをWorkersに統合しつつある。Pagesが明日なくなるわけではないが、新機能はすべてWorkers側にのみ追加されている。筆者は2026年初頭に全PagesプロジェクトをWorkersへ移行し、その過程でつまずいたポイントをまとめた。
本記事はcogley.jpの完全版の要約版です。各機能の詳細な解説、CI/CDの全パターン、トラブルシューティングツリーなどは完全版をご覧ください。
PagesとWorkersの機能比較
Workersテックリードの Kenton Varda 氏は「Pages固有の機能をすべて汎用的なWorkers機能に変えていく」と述べている。公式の互換性マトリクスを見ると、差は拡大し続けている。
| 機能 | Pages | Workers |
|---|---|---|
| 静的アセット / SSR | ✓ | ✓ |
| Durable Objects | 別途Workerが必要 | ネイティブ対応 |
| Cronトリガー | ✗ | ✓ |
| Queue Consumer | ✗ | ✓ |
| Email Workers(受信) | ✗ | ✓ |
| 画像リサイズバインディング | ✗ | ✓ |
| レート制限 | ✗ | ✓ |
| Workers Logs | 基本のみ | フルオブザーバビリティ |
| Tail Workers / ソースマップ | ✗ | ✓ |
| 段階的デプロイ | ✗ | ✓ |
| Smart Placement / Secrets Store | ✗ | ✓ |
移行プロセス概要
設定の変換
Pages設定:
{
"name": "my-project",
"pages_build_output_dir": "./dist/client/",
}
Workers設定:
{
"name": "my-project",
"compatibility_date": "2026-03-01",
"compatibility_flags": ["nodejs_compat"],
"main": "./dist/server/index.js",
"assets": {
"directory": "./dist/client/",
"binding": "ASSETS",
"not_found_handling": "single-page-application",
},
}
主な変更点:
-
pages_build_output_dir→assets.directory -
mainでサーバーエントリポイントを指定 -
compatibility_dateを追加(必須) -
compatibility_flags: ["nodejs_compat"]でNode.js APIポリフィルを有効化 - 404ハンドリングを明示的に設定
静的サイトの場合
{
"name": "my-static-site",
"compatibility_date": "2026-03-01",
"assets": {
"directory": "./dist/",
"not_found_handling": "404-page",
},
}
.assetsignore の作成
Pagesは node_modules 等を自動除外していたが、Workersでは明示的に指定する。
node_modules
.git
.DS_Store
.env*
*.map
SvelteKitで
@sveltejs/adapter-cloudflareを使う場合は、アダプタが自動処理するため通常不要。
SvelteKit移行
アダプタを更新する。
npm install -D @sveltejs/adapter-cloudflare
svelte.config.js:
import adapter from '@sveltejs/adapter-cloudflare';
export default {
kit: {
adapter: adapter({
routes: {
include: ['/*'],
exclude: ['<all>'],
},
platformProxy: {
configPath: './wrangler.jsonc',
persist: { path: '.wrangler/state/v3' },
},
}),
},
};
wrangler.jsonc:
{
"name": "my-sveltekit-app",
"compatibility_date": "2026-03-01",
"compatibility_flags": ["nodejs_compat"],
"main": ".svelte-kit/cloudflare/_worker.js",
"assets": {
"directory": ".svelte-kit/cloudflare",
"binding": "ASSETS",
},
"workers_dev": true,
"preview_urls": true,
}
注意:
@sveltejs/adapter-cloudflareの出力先は.svelte-kit/cloudflare/であり、./dist/ではない。パスを間違えると「Worker not found」エラーになる。
バインディングへのアクセスは platform.env 経由:
// +page.server.ts
export async function load({ platform }) {
const db = platform?.env?.DB;
const result = await db?.prepare('SELECT * FROM posts').all();
return { posts: result?.results ?? [] };
}
ドメイン移行:最も難しいポイント
カスタムドメインの移行が単純でない理由:
- ドメインがPagesに紐づいている間は、Workersにドメインを追加できない
- Pagesから先に削除するとダウンタイムが発生する
解決策はAPIによるアトミックな切り替えだ。
アトミックなドメイン切り替えスクリプト
#!/bin/bash
set -e
ACCOUNT_ID="your-account-id"
ZONE_ID="your-zone-id"
API_TOKEN="your-api-token"
PAGES_PROJECT="old-pages-project"
WORKERS_SCRIPT="new-workers-project"
DOMAIN="yourdomain.com"
echo "Removing domain from Pages..."
curl -s -X DELETE \
"https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/pages/projects/${PAGES_PROJECT}/domains/${DOMAIN}" \
-H "Authorization: Bearer ${API_TOKEN}"
echo "Adding Workers route for root domain..."
curl -s -X POST \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/workers/routes" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"pattern": "'"${DOMAIN}"'/*",
"script": "'"${WORKERS_SCRIPT}"'"
}'
echo "Adding Workers route for www subdomain..."
curl -s -X POST \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/workers/routes" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"pattern": "www.'"${DOMAIN}"'/*",
"script": "'"${WORKERS_SCRIPT}"'"
}'
echo "Done! Domain switched to Workers."
ダウンタイムは2〜5秒程度。切り替え後は両ドメインのテストと「Always Use HTTPS」の有効化を忘れずに。
Workers移行後に使える主な機能
Service Bindings
ネットワークオーバーヘッドなしで複数Workerを接続。トラフィックはCloudflareのネットワーク内にとどまる。
{
"services": [
{
"binding": "AUTH_SERVICE",
"service": "auth-worker",
},
],
}
D1リードレプリケーション
リードレプリカ使用時はD1 Sessionsでread-after-write整合性を確保する。
// セッションを使わないと書き込み直後に古いデータを読む可能性あり
const db = env.DB.withSession();
await db.prepare('INSERT INTO posts (title) VALUES (?)').bind('New Post').run();
const posts = await db.prepare('SELECT * FROM posts').all(); // 確実にinsertが含まれる
オブザーバビリティ
{
"observability": {
"enabled": true,
"head_sampling_rate": 1,
"logs": { "enabled": true, "head_sampling_rate": 1, "invocation_logs": true },
"traces": { "enabled": true, "head_sampling_rate": 1 },
},
}
よくあるトラブルと対処法
| 症状 | 原因 | 対処法 |
|---|---|---|
fs/path/process エラー |
nodejs_compat フラグ未設定 |
compatibility_flags に追加 |
| 522タイムアウト | 誤ったCNAME設定 | Workers routesを使用 |
| ルートで404 |
not_found_handling 未設定 |
single-page-application か 404-page を設定 |
| 認証失敗 | シークレット未同期 |
wrangler secret put で再設定 |
| バンドルサイズ超過 | 10MB制限 | Vite 8へアップグレード、ダイナミックインポート |
| エラー10021 | Secrets Store権限不足 | トークンにEdit権限を追加 |
| Pages削除不可 | デプロイ500件超 | APIでバッチ削除 |
移行後チェックリスト
- 全カスタムドメインでサイトが正しく読み込まれる
- ルートとwwwの両方が動作する
- HTTPSが強制されている
- 環境変数とシークレットが設定済み
- データベースバインディング(D1、KV、R2)が動作する
- オブザーバビリティ/ログが有効
- CI/CDが正常にデプロイする
まとめ
2026年3月時点で、WorkersはPagesの全機能をカバーしている。強制移行の期限は未発表だが、新機能の差は広がり続けている。新規プロジェクトはWorkersで始めるべきだ。既存Pagesプロジェクトは、自分のスケジュールでコントロールできるうちに移行するのがよい。
ドメイン切り替え以外はすべて設定変更のみで、ドメイン切り替えも上記のアトミックAPIアプローチで2〜5秒のダウンタイムに抑えられる。
参考資料:
この記事は cogley.jp に掲載されたものです。
Rick Cogley(コグレー・リック)は株式会社イソリアのCEO兼創業者。東京で日英バイリンガルITアウトソーシングとインフラサービスを提供中。