- wrangler.jsonc の主要キー(name / main / compatibility_date / vars / triggers)を読み書きできる
- 環境変数(vars)とシークレットを使い分け、ローカルと本番それぞれで安全に設定できる
- バインディングの概念を理解し、KV / R2 / D1 などへ接続する「型」を掴む
- Cron Triggers と scheduled ハンドラで Worker を定期実行できる
- 複数環境(staging / production)の出し分けと、Cache API / fetch の cf オプションの初歩
wrangler.jsonc を読み解く
第 2 章では最小構成の Worker をデプロイしました。この章の主役は、プロジェクトの振る舞いを決める設定ファイル wrangler.jsonc です。Wrangler v3.91.0 以降は JSON 形式(wrangler.jsonc)と TOML 形式(wrangler.toml)の両方をサポートしており、設定の意味はどちらでも同じです。Cloudflare は新規プロジェクトに wrangler.jsonc を推奨しており(一部の新機能は JSON 形式のみ)、本書もこれを既定とします。
典型的な設定ファイルは次のようになります。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
// 新規作成時は「今日の日付」を設定する
"compatibility_date": "2026-08-10",
"compatibility_flags": ["nodejs_compat"],
// *.workers.dev への公開(既定は true)
"workers_dev": true,
// 平文の環境変数
"vars": {
"API_HOST": "api.example.com"
},
// 定期実行(後述の Cron Triggers)
"triggers": {
"crons": ["0 0 * * *"]
}
}
デプロイに最低限必要なのは name・main・compatibility_date の 3 キーです。
| キー | 必須 | 役割 |
|---|---|---|
name | 必須 | Worker 名。英数字とハイフンのみ(アンダースコア不可) |
main | 必須 | エントリポイントのパス(例: ./src/index.ts) |
compatibility_date | 必須 | 利用するランタイム挙動を固定する日付 |
compatibility_flags | 任意 | 個別機能のオプトイン / オプトアウト |
workers_dev | 任意 | *.workers.dev での公開可否(既定 true) |
vars | 任意 | 平文の環境変数(文字列・JSON 値) |
triggers | 任意 | Cron Triggers(cron 式の配列) |
env | 任意 | 名前付き環境(staging 等)ごとの設定 |
kv_namespaces など | 任意 | 各種バインディングの宣言(後述) |
運用の大原則は「設定ファイルを Source of Truth にする」ことです。ダッシュボード側で変更しても、次の npx wrangler deploy で設定ファイルの内容に上書きされます(シークレットは例外で、wrangler secret delete などで明示的に削除しない限り消えません)。全キーの詳細は Configuration リファレンスを参照してください。
compatibility date と compatibility flags
Workers ランタイムは常時更新されますが、後方互換性を壊しうる修正にはそれぞれ「既定で有効になる日付」があり、その日付以降の compatibility_date を設定した Worker にだけ適用されます。つまり「どの時点のランタイム挙動に固定するか」の宣言です。プロジェクト開始時に当日の日付を設定し、以後もときどき更新してテストします。古い日付は永続的にサポートされますが、新機能には新しい日付を要求するものがあります。
compatibility_flags は個別機能単位のスイッチです。代表例が Node.js API 群を有効化する nodejs_compat フラグで、compatibility date を 2024-09-23 以降にして指定すると Node.js 互換 API とポリフィルが使えます。各フラグの既定化日は Compatibility flags のページに一覧があります。
複数環境(environments)
同じコードベースを staging / production など複数の設定で運用したいときは、env キーに名前付き環境を定義します。環境名 staging で deploy すると、Cloudflare 上には <トップレベル name>-<環境名>(例: my-worker-staging)という別の Worker が作られます。コマンドは --env(短縮 -e)フラグで環境を選びます(例: npx wrangler deploy --env staging)。
注意すべきは継承ルールです。route や compatibility_date などほとんどのキーはトップレベルから環境に継承されますが、vars とバインディング類(kv_namespaces など)は継承されない(non-inheritable)ため、環境ごとに明示的に定義します。詳細は Environments のドキュメントを参照してください。
vars とバインディングは中段の再定義を通って初めて届き、それを飛ばした破線の経路でも Worker 自体は問題なく作られます。--env を付けた途端に値だけが消えたように見えるのはこのためです。バインディング — env オブジェクトの全体像
バインディングは、Worker から Cloudflare 上のリソース(KV / R2 / D1 など)へアクセスするための仕組みです。設定ファイルで宣言すると、ハンドラの第 2 引数 env オブジェクトにそのリソースの API が「生えて」きます。本質は権限と API が一体になったもので、アクセスキーやトークンをコードに持ち込む必要がなく、資格情報が Worker のコードに渡らないため漏洩のしようがありません。REST API 経由より高速で制約も少なくなります。
put() が届くのに対し、REST API 経由では公開エンドポイントが 1 段入ります。左下にぶら下がる「支え」も、設定 1 行から保管とローテーションが要るトークンへ変わります。たとえば R2 バケットのバインディングはこう宣言します。
{
"r2_buckets": [
{
"binding": "MY_BUCKET",
"bucket_name": "<MY_BUCKET_NAME>"
}
]
}
binding に指定した名前が env のプロパティ名になり、await env.MY_BUCKET.put(key, request.body) のように呼び出せます(<MY_BUCKET_NAME> は自分のバケット名に置き換えます)。ローカル開発時は既定でローカルにシミュレートされたリソースへ接続されるため、本番データを汚す心配はありません。主要なバインディングは次の通りです。
| 設定キー | リソース | 概要 |
|---|---|---|
vars / シークレット | 環境変数 | 文字列・JSON 値。シークレットは暗号化される(本節後半) |
kv_namespaces | Workers KV | グローバルな低レイテンシ key-value ストア |
r2_buckets | R2 | S3 互換・egress 無料のオブジェクトストレージ |
d1_databases | D1 | サーバーレス SQL データベース |
durable_objects.bindings | Durable Objects | 強整合なストレージと協調処理 |
queues.producers | Queues | 配信保証つきメッセージキュー |
ai | Workers AI | モデル推論。ローカル開発でも実アカウントで実行され課金対象(2026-08 時点) |
services | Service bindings | 公開 URL を経由しない Worker 間呼び出し(RPC / HTTP) |
KV / R2 / D1 / Durable Objects / Queues は第 II 部で、Workers AI は第 III 部で手を動かして学びます。Service bindings は services に相手の Worker 名を書くだけで、await env.WORKER_B.add(1, 2) のような RPC 呼び出しができます(Service bindings)。
env へのアクセス方法は 3 つあります。①ハンドラの引数として受け取る、②WorkerEntrypoint 等のクラスプロパティ this.env として使う、③import { env } from "cloudflare:workers" でどこからでも import する、です。③はトップレベルで設定値を読むのに便利ですが、Workers はリクエストコンテキスト外の I/O を許可しないため、トップレベルで使えるのは環境変数・シークレットの参照などに限られ、KV の読み書きなどの I/O はハンドラ内で行います。
vars とシークレットの使い分け
環境変数(vars)は平文で、API のホスト名など「見えてもよい設定値」向けです。一方シークレットは暗号化された環境変数で、一度定義すると Wrangler からもダッシュボードからも値を見られません。API キーなどの機密情報は必ずシークレットにし、vars に書いてはいけません。Worker のコードから見ると両者に区別はなく、どちらも env.API_TOKEN のように参照できます。
ローカルと本番でのシークレット設定
ローカル開発では、設定ファイルと同じディレクトリに .dev.vars(または .env)を置き、dotenv 形式で書きます。両方は併用できず、.dev.vars があると .env は読み込まれません。git にはコミットせず、.gitignore に .dev.vars* と .env* を追加してください。環境ごとに変えたいときは .dev.vars.staging のような環境名つきファイルを作ります。
デプロイ済み Worker へのシークレット登録は npx wrangler secret put <KEY> です。このコマンドは新しいバージョンを作って即座にデプロイします(段階的デプロイ運用では wrangler versions secret put)。また設定ファイルの secrets.required に必要なシークレット名を列挙しておくと、未設定のまま deploy したときに明確なエラーで失敗させられます。
env.API_TOKEN でも上の経路はローカル実行にしか届かず、本番へ値を運ぶのは下の経路だけなので、本番で undefined が出たらコードではなく「どちらの経路を通したか」を疑ってください。Cron Triggers と scheduled ハンドラ
Cron Triggers は cron 式で Worker を定期実行する仕組みで、メンテナンスジョブや外部 API の定期取得に向いています。HTTP リクエストの代わりに scheduled(controller, env, ctx) ハンドラが呼ばれ、controller.cron(発火した cron 式そのもの)と controller.scheduledTime(予定時刻のエポックミリ秒)が参照できます。ランタイムは scheduled() が返す Promise の解決を(実行時間上限の 15 分まで、2026-08 時点)待つため、単一の非同期処理に ctx.waitUntil() は必須ではありません。複数タスクの並行実行や、特定の Promise の成否を Cron の実行結果として記録したいときに使います。
scheduled() を直接呼びます。破線のローカルテストは合流点が示すとおり同じ入口を HTTP で代用する仕組みなので、叩いた後に見るログは fetch() ではなく scheduled() 側です。cron 式は 5 フィールドで、Quartz 風の拡張文字もサポートされます。
| フィールド | 値 | 使える文字 |
|---|---|---|
| 分 | 0-59 | * , - / |
| 時 | 0-23 | * , - / |
| 日 | 1-31 | * , - / L W |
| 月 | 1-12 または JAN 等の 3 文字略称 | * , - / |
| 曜日 | 1-7 または SUN 等の 3 文字略称 | * , - / L # |
注意点は 2 つ。第一に、Cron Triggers は UTC で実行されます。日本時間(JST)は UTC+9 なので、毎朝 9:00 JST なら 0 0 * * *(UTC 0:00)です。第二に、曜日フィールドは 1 = 日曜〜7 = 土曜で、0 = 日曜とする他の cron 実装と異なります。曖昧さを避けるため SUN や MON-FRI のような略称が推奨されています。
複数の cron 式を設定した場合、どれが発火しても同じ scheduled() が呼ばれるため、controller.cron の値で分岐します(比較文字列は設定ファイルの cron 式とスペースまで含めた完全一致)。ローカルでのテストは、wrangler dev 中に公開される /cdn-cgi/handler/scheduled エンドポイントへ HTTP リクエストを送るだけです(ハンズオン 3-2 で試します)。
キャッシュの初歩 — fetch の cf オプションと Cache API
Workers から Cloudflare のキャッシュを操作する方法は 2 つあります。1 つ目は fetch() のオプションで、サブリクエストのキャッシュ挙動を cf オブジェクトで制御します。
export default {
async fetch(request): Promise<Response> {
let response = await fetch(request, {
cf: {
// Content-Type を問わずキャッシュし、300 秒後に再検証する
cacheTtl: 300,
cacheEverything: true,
// cacheKey: "..." // カスタムキャッシュキーは Enterprise プラン限定
},
});
// ヘッダを書き換えられるよう Response を再構築する
response = new Response(response.body, response);
// ブラウザ側キャッシュは 25 分
response.headers.set("Cache-Control", "max-age=1500");
return response;
},
} satisfies ExportedHandler;
キャッシュに載ったかはレスポンスヘッダの CF-Cache-Status(ヒット時 HIT)で確認できます。2 つ目は Cache API です。リクエスト URL をキー、Response を値とするキャッシュストアで、Worker 自身が生成したレスポンスも保存できます。
export default {
async fetch(request, env, ctx): Promise<Response> {
const cacheKey = new Request(new URL(request.url).toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
response = await fetch(request); // オリジンから取得
response = new Response(response.body, response);
// Cache API は Cache-Control を尊重する(最大 10 秒キャッシュ)
response.headers.append("Cache-Control", "s-maxage=10");
ctx.waitUntil(cache.put(cacheKey, response.clone()));
}
return response;
},
} satisfies ExportedHandler;
使い分けの指針: オリジンへサブリクエストを送る「ミドルウェア」型なら fetch のキャッシュを推奨、Worker 自身がレスポンスを生成する構成なら Cache API です。制約として、Cache API は Tiered Cache と互換性がなく、cache.match / put / delete はその Worker が動いたデータセンターのローカルキャッシュにのみ作用します。caches.default は fetch と共有される既定キャッシュで、await caches.open(名前) で分離された名前空間も作れます。詳細は How the Cache works を参照してください。
vars とシークレットを両方使う Worker を作り、ローカルと本番の設定フローを一巡します。所要時間の目安は 15 分です。
- 第 1 章の手順で新規プロジェクトを作成します(
npm create cloudflare@latest my-config-worker、Hello World テンプレートを選択) wrangler.jsoncにvarsを追加します:{ "name": "my-config-worker", "main": "src/index.ts", "compatibility_date": "2026-08-10", "vars": { "API_HOST": "api.example.com" } }src/index.tsを書き換え、平文のAPI_HOSTとシークレットのAPI_TOKENを両方読みます:export interface Env { API_HOST: string; API_TOKEN: string; } export default { async fetch(request, env, ctx): Promise<Response> { return Response.json({ host: env.API_HOST, tokenConfigured: typeof env.API_TOKEN === "string", }); }, } satisfies ExportedHandler<Env>;- ローカル用シークレットを
.dev.varsに置いて動作確認し、デプロイ後に本番シークレットを登録します:echo 'API_TOKEN="local-dev-token"' > .dev.vars npx wrangler dev # 別ターミナルで: curl http://localhost:8787 # 本番へ。まず deploy してから secret put する npx wrangler deploy npx wrangler secret put API_TOKEN # プロンプトに本番用の値を入力(新バージョンが即デプロイされる)
ローカル・本番どちらでも {"host":"api.example.com","tokenConfigured":true} が返れば成功です。.dev.vars の .gitignore 追加も忘れずに。
2 本の cron スケジュールを持つ Worker を作り、ローカルで発火をシミュレートしてからデプロイします。所要時間の目安は 15 分です。
- ハンズオン 3-1 のプロジェクトの
src/index.tsにscheduledハンドラを追加します:export default { async fetch(request, env, ctx): Promise<Response> { return new Response("This Worker also runs on a schedule."); }, async scheduled(controller, env, ctx): Promise<void> { switch (controller.cron) { case "*/5 * * * *": console.log("5 分ごとの同期ジョブ"); break; case "0 0 * * *": // JST では毎朝 9:00 const at = new Date(controller.scheduledTime).toISOString(); console.log(`daily job scheduled at ${at}`); break; } }, } satisfies ExportedHandler; wrangler.jsoncにtriggersを追加します:{ "triggers": { "crons": ["*/5 * * * *", "0 0 * * *"] } }npx wrangler devを起動し、別ターミナルからテスト用エンドポイントを叩いて発火させます:curl "http://localhost:8787/cdn-cgi/handler/scheduled?cron=0+0+*+*+*&format=json"{"outcome":"ok","noRetry":false}が返り、dev 側ログにdaily job scheduled at ...が出ることを確認しますnpx wrangler deployでデプロイします。実行履歴はダッシュボードの対象 Worker > Settings > Trigger Events で確認でき、直近 100 件が記録されます(2026-08 時点)
Cron Trigger の追加・変更が全ネットワークへ伝播するまで最大 15 分かかります(2026-08 時点)。
同じコードを 2 環境にデプロイし、環境ごとに異なる vars が渡ることを確認します。所要時間の目安は 10 分です。
wrangler.jsoncにenvを追加します。varsは継承されないため、環境ごとに定義します:{ "name": "my-config-worker", "vars": { "ENVIRONMENT": "dev" }, "env": { "staging": { "vars": { "ENVIRONMENT": "staging" } }, "production": { "vars": { "ENVIRONMENT": "production" } } } }src/index.tsのレスポンスにenv.ENVIRONMENTを含めて、どの環境で動いているか見えるようにします- 環境を指定してデプロイし、Worker 名にサフィックスが付くことを確認します:
npx wrangler deploy --env staging # Uploaded my-config-worker-staging # Published my-config-worker-staging npx wrangler deploy --env production # Uploaded my-config-worker-production - それぞれの workers.dev URL にアクセスし、
ENVIRONMENTの値が環境ごとに変わることを確認します
環境ごとに別 Worker として作られるため、シークレットも環境単位で npx wrangler secret put API_TOKEN --env staging のように登録します。
つまずきポイント
.dev.vars に書いたのに本番で undefined になる — .dev.vars / .env はローカル開発専用で、デプロイには一切反映されません。本番のシークレットは npx wrangler secret put <KEY>(または deploy 時の --secrets-file)で別途登録します。
cron が指定した時刻に動かない — Cron Triggers は UTC 実行です。JST のつもりで書くと 9 時間ずれます。設定変更の伝播には最大 15 分かかります(2026-08 時点)。また crons キーをコメントアウトしただけでは既存トリガーは残り続けます。消すには空配列 "crons": [] をデプロイしてください。
--env を付けたら vars やバインディングが消えた — vars・kv_namespaces などのバインディング類は non-inheritable で、トップレベルから環境へ継承されません。環境ごとに再定義が必要です。
シークレットを更新したのに古い値が使われ続ける — バインディングだけを変更したデプロイでは実行中の isolate が再利用されることがあり、グローバルスコープに env.MY_SECRET から作ったクライアントをキャッシュしていると古い値を持つインスタンスが生き残ります。env 由来のオブジェクトはリクエストごとにハンドラ内で生成してください。
理解度チェック
Q1. 環境変数(vars)とシークレットの違いは? Worker のコードからの見え方は?
vars は平文、シークレットは暗号化され定義後は値を見られません。コードからはどちらも env.KEY として同じ形で参照でき、区別はありません。機密情報は必ずシークレットにします。
Q2. 毎朝 9:00 JST に Worker を実行したい。cron 式はどう書く?
0 0 * * * です。Cron Triggers は UTC で実行されるため、JST(UTC+9)の 9:00 は UTC の 0:00 に相当します。
Q3. env.staging を定義したとき、トップレベルから自動継承されない設定はどれ?
vars とバインディング類(kv_namespaces など)です。non-inheritable なので環境ごとに明示的に定義します。compatibility_date や route などは継承されます。
Q4. compatibility_date を古い日付のまま放置すると Worker は壊れる?
壊れません。古い日付のランタイム挙動は永続的にサポートされます。ただし新機能には新しい日付を要求するものがあるため、定期的な更新とテストが推奨されています。
Q5. Worker 自身が生成したレスポンスをキャッシュしたい。fetch の cf オプションと Cache API のどちらを使う?
Cache API(cache.put())です。fetch の cf オプションはサブリクエストのキャッシュ制御用で、Worker が生成したレスポンスには使えません。Cache API はデータセンターローカルで Tiered Cache 非対応です。
まとめと次章へ
- wrangler.jsonc が Worker 設定の Source of Truth。必須は
name/main/compatibility_dateの 3 キー - vars は平文の設定値、シークレットは暗号化された機密値。ローカルは
.dev.vars、本番はwrangler secret put - バインディングは「権限と API の一体化」。宣言すると
envにリソースの API が生える - Cron Triggers(UTC・曜日は 1=日曜)と
scheduled()で定期実行。ローカルは/cdn-cgi/handler/scheduledでテスト - 環境(
env.staging等)は別 Worker としてデプロイされ、vars・バインディングは継承されない - キャッシュはサブリクエストなら fetch の
cfオプション、自前レスポンスなら Cache API
次章では、この設定を土台に静的アセットの配信とフルスタック構成へ進みます。バインディングの各論は第 II 部で 1 つずつ深掘りします。