Worker のコードは、Cloudflare のネットワークへデプロイする前に、自分のマシン上でビルド、実行、テストできます。これを可能にしているのが Miniflare です。本番と同じランタイム workerd ↗ で Worker コードを実行するシミュレーターです。
既定では、Worker のバインディングは ローカルでシミュレートしたリソース に接続します。リモートバインディング を設定すると、本番の実リソースとやり取りできます。
Workers を開発するときは、次の 2 つを区別して考えることが大切です。
-
Worker の実行: Worker コードが実際に動く場所です(自分のマシンか、Cloudflare のインフラか)。
-
バインディング: Worker が Cloudflare のリソース(KV 名前空間、R2 バケット、D1 データベース、Queues、Durable Objects など)とやり取りする方法です。Worker コードでは
envオブジェクト経由でアクセスします(例:env.MY_KV)。
ローカル開発サーバーは、次のいずれかで起動できます。
- Cloudflare Workers CLI の Wrangler と、組み込みの
wrangler devコマンド。
npx wrangler devyarn wrangler devpnpm wrangler devnpx vite devyarn vite devpnpm vite devWrangler も Cloudflare Vite plugin も、内部では Miniflare を使います。どちらも Cloudflare チームが開発・保守しています。Wrangler と Vite の使い分けは、ガイド Wrangler と Vite の選択 を参照してください。
既定では、wrangler dev / vite dev(Vite plugin 使用時)は次のように動きます。
- Worker コードは自分のマシン上で実行されます。
- Wrangler 設定 でバインドしたリソースは、すべてローカルでシミュレートされます。
- ローカルの
workerdランタイムはTZ=UTCで動きます。Worker 内のDateとIntlAPI は UTC を観測し、マシンのタイムゾーンに関係なく本番の Cloudflare ランタイムと揃います。
バインディング は、Worker が各種 Cloudflare リソース(KV 名前空間、R2 バケット、D1 データベース、Queues、Durable Objects など)とやり取りするためのインターフェイスです。Worker コードでは env オブジェクト経由でアクセスします(例: env.MY_KV)。
ローカル開発中も、デプロイ先と同じ API 呼び出し(例: env.MY_KV.put())でこれらのバインディングを使います。ローカルリソースは最初は空です。データの入れ方は ローカルデータの追加 を参照してください。
- 既定では、バインディングは ローカルのリソースシミュレーション に接続します(AI バインディング を除く。AI モデルは常にリモートで動きます)。
- この既定動作は上書きでき、バインディングごとに リモートバインディング で リモートリソースへ接続 できます。Worker コードはローカルのまま、本番の実リソースに接続できます。
wrangler devでは、--localフラグ(wrangler dev --local)を付けると、すべての リモートバインディング を一時的に無効化し、ローカルリソースだけに接続できます。
リモートバインディング は、ローカル開発中にローカルシミュレーションではなく、デプロイ済みのリモートリソースへ接続するよう設定したバインディングです。リモートバインディングは Wrangler、Cloudflare Vite plugin、@cloudflare/vitest-plugin パッケージで使えます。バインディング定義で remote: true を設定します。
{
"name": "my-worker",
// Set this to today's date
"compatibility_date": "2026-09-20",
"r2_buckets": [
{
"bucket_name": "screenshots-bucket",
"binding": "screenshots_bucket",
"remote": true,
},
],
}name = "my-worker"
# Set this to today's date
compatibility_date = "2026-09-20"
[[r2_buckets]]
bucket_name = "screenshots-bucket"
binding = "screenshots_bucket"
remote = trueリモートバインディングを設定しても、Worker の 実行はローカル のままです。変わるのは、バインディングが接続する先のリソースだけです。remote: true が付いたバインディングについて、Miniflare はその操作(例: env.MY_KV.put())をデプロイ済みリソースへ送ります。remote: true を明示していないバインディングは、既定どおりローカルシミュレーションを使います。
リモートバインディングは Workers Environments と相性が良いです。本番データを守るために、開発用またはステージング用の環境を作り、Wrangler 設定 で本番とは別のリソースを指定できます。
例:
{
"name": "my-worker",
// Set this to today's date
"compatibility_date": "2026-09-20",
"env": {
"production": {
"r2_buckets": [
{
"bucket_name": "screenshots-bucket",
"binding": "screenshots_bucket",
},
],
},
"staging": {
"r2_buckets": [
{
"bucket_name": "preview-screenshots-bucket",
"binding": "screenshots_bucket",
"remote": true,
},
],
},
},
}name = "my-worker"
# Set this to today's date
compatibility_date = "2026-09-20"
[[env.production.r2_buckets]]
bucket_name = "screenshots-bucket"
binding = "screenshots_bucket"
[[env.staging.r2_buckets]]
bucket_name = "preview-screenshots-bucket"
binding = "screenshots_bucket"
remote = true上記の設定で wrangler dev -e staging(または CLOUDFLARE_ENV=staging vite dev)を実行すると、次のようになります。
- Worker コードはローカルで動きます
env.screenshots_bucketへの呼び出しは、本番のscreenshots-bucketではなくpreview-screenshots-bucketを使います。
一部のバインディングは、リモート側へ接続する設定をおすすめします。Cloudflare のネットワークインフラに依存していたり、ローカルでは十分にシミュレートできない複雑なバックエンドを持つことが多いためです。
次のバインディングは、Wrangler 設定で remote: true を付けることを推奨します。
描画用の実際のヘッドレスブラウザとやり取りします。Browser Run のローカルシミュレーションは、現時点ではありません。
{
"browser": {
"binding": "MY_BROWSER",
"remote": true
},
}[browser]
binding = "MY_BROWSER"
remote = trueCloudflare のネットワーク上にデプロイされた実際の AI モデルで推論します。Workers AI のローカルシミュレーションは、現時点ではありません。
{
"ai": {
"binding": "AI",
"remote": true
},
}[ai]
binding = "AI"
remote = true本番の Vectorize インデックスに接続し、正確なベクトル検索と類似度演算を行います。Vectorize のローカルシミュレーションは、現時点ではありません。
{
"vectorize": [
{
"binding": "MY_VECTORIZE_INDEX",
"index_name": "my-prod-index",
"remote": true
}
],
}[[vectorize]]
binding = "MY_VECTORIZE_INDEX"
index_name = "my-prod-index"
remote = truemTLS:
証明書の交換と検証が期待どおり動くことを確認します。mTLS バインディングのローカルシミュレーションは、現時点ではありません。
{
"mtls_certificates": [
{
"binding": "MY_CLIENT_CERT_FETCHER",
"certificate_id": "<YOUR_UPLOADED_CERT_ID>",
"remote": true
}
]
}[[mtls_certificates]]
binding = "MY_CLIENT_CERT_FETCHER"
certificate_id = "<YOUR_UPLOADED_CERT_ID>"
remote = trueImages API の高忠実度版へ接続し、変換が期待どおり動くことを確認します。Cloudflare Images のローカルシミュレーションは 一部の機能だけに限られます。
{
"images": {
"binding": "IMAGES" ,
"remote": true
}
}[images]
binding = "IMAGES"
remote = trueWorkers for Platforms の利用者は、dispatch namespace バインディング定義で remote: true を設定できます。
{
"dispatch_namespaces": [
{
"binding": "DISPATCH_NAMESPACE",
"namespace": "testing",
"remote":true
}
]
}[[dispatch_namespaces]]
binding = "DISPATCH_NAMESPACE"
namespace = "testing"
remote = trueこれにより、動的ディスパッチ Worker をローカルで動かしつつ、リモートの dispatch namespace バインディングへ接続できます。コアのディスパッチロジックの変更を、実際にデプロイされた ユーザー Worker に対してテストできます。
一部のバインディングは、ローカル開発中のリモート接続(remote: true)に対応していません。これらは常にローカルシミュレーション、またはローカルの値を使います。
次の非対応バインディング種別で Wrangler 設定に remote: true を指定すると、Cloudflare は エラーを出します。リモートバインディングの対応・非対応一覧 を参照してください。
-
Durable Objects: Durable Objects のリモート接続は将来対応する可能性がありますが、現時点では常にローカルで動きます。ただし、Durable Objects とリモートバインディングの併用は可能です。後述の Durable Objects と Workflows でリモートリソースを使う を参照してください。
-
Workflows: Workflows のリモート接続は将来対応する可能性がありますが、現時点ではローカルでのみ動きます。ただし、Workflows とリモートバインディングの併用は可能です。後述の Durable Objects と Workflows でリモートリソースを使う を参照してください。
-
環境変数(
vars): 環境変数は、ローカル開発とデプロイ先で別の値にすることを想定しています。ローカルでは(.dev.varsファイルや Wrangler 設定など)簡単に設定できます。 -
Secrets: 環境変数と同様、セキュリティ上、ローカル開発とデプロイ先で値を分ける想定です。ローカルのシークレット管理には
.dev.varsを使います。 -
静的アセット: 開発中の静的アセットは、速度と変更の即時反映のため、常にローカルディスクから配信されます。
-
Version Metadata: Worker コードはローカルで動いているため、特定のデプロイ版に紐づくバージョンメタデータ(コミットハッシュ、バージョンタグなど)は該当せず、正確でもありません。
-
Analytics Engine: ローカル開発セッションは、通常、本番の Analytics Engine に直接データを送りません。
-
Hyperdrive: 現在対応作業中ですが、現時点では非対応です。
-
Rate Limiting: ローカル開発セッションは、通常、デプロイ済み Worker のレート制限を共有したり影響したりすべきではありません。レート制限のロジックはローカルシミュレーションでテストしてください。
Durable Object と Workflow のバインディングは、現時点ではリモートにできません。それでもローカル開発中に使い、リモートリソースとやり取りすることはできます。
おすすめのパターンは次の 2 つです。
-
ローカルの Durable Objects / Workflows とリモートバインディング:
Wrangler 設定 でリモートバインディングを有効にすると、ローカルで動いている Durable Objects と Workflows からリモートリソースへアクセスできます。これらのバインディングはローカル実行のまま、ローカル開発中にリモートリソースとやり取りできます。
-
サービスバインディング経由でリモートの Durable Objects / Workflows にアクセスする:
リモートの Durable Object または Workflow インスタンスとやり取りするには、それらを定義した Worker をデプロイします。次に、ローカルの Worker で、デプロイ済み Worker を指すリモートの サービスバインディング を設定します。 ローカルの Worker はリモートのデプロイ済み Worker とやり取りでき、その Worker がリモートの Durable Objects / Workflows と通信します。この方法では、リモートのサービスバインディングを通信路にし、デプロイ済み Worker をローカル開発中のリモートバインディングへのプロキシとして使えます。
-
Cloudflare Access: Worker が Cloudflare Access で保護されている場合、Wrangler はリモートバインディングへ接続するときに Access で認証する必要があります。Access で保護された Worker に接続する を参照してください。
-
データの変更: リモート接続したバインディングへの操作(書き込み、削除、更新)は、対象の Cloudflare リソース(プレビューでも本番でも)の実データに影響します。
-
課金: これらの接続経由でリモートの Cloudflare サービスとやり取りすると、そのサービスの通常の運用コストが発生します(KV 操作、R2 のストレージ / 操作、AI リクエスト、D1 の使用量など)。
-
ネットワーク遅延: リモート接続したバインディングの操作には、インターネット経由の通信があるため、ネットワーク遅延を見込んでください。
Worker が Cloudflare Access で保護されている場合、Wrangler はリモートバインディングへ接続するときに Access で認証する必要があります。Access が Worker 本体、アカウント内のすべての Worker、workers.dev ホスト名、カスタムドメイン、または Worker へルーティングする別のホスト名やパスを保護している場合も同じです。
Access への認証方法は次の 2 通りです。
-
対話型ログイン(ローカル開発): ユーザーログインを受け付けるポリシーがある場合、Wrangler はブラウザで対話型の
cloudflared access loginフローを起動します。正しいアカウントにサインインしていれば、追加の設定は不要です。ポリシーがサービストークン認証だけを許可している場合、Wrangler は対話型フローをスキップし、サービストークンの認証情報が必要である旨のエラーを出します。 -
サービストークン(CI / 非対話環境): CI/CD パイプラインなど非対話の場面、またはポリシーがサービストークン認証だけを許可する場合、Wrangler はブラウザの対話型フローを起動できません。代わりに Cloudflare Access のサービストークン で認証する必要があります。非対話環境でサービストークンを設定しないと、Wrangler は対話型フローを試さずエラーを出します。
サービストークン認証の設定手順は次のとおりです。
-
サービストークンを作成します。
Cloudflare ダッシュボードで Zero Trust > Access > Service Auth > Service Tokens を開き、新しいトークンを作成します。詳細は Service tokens を参照してください。Client ID と Client Secret が表示されるので、安全な場所に保存してください。シークレットは再表示されません。
-
Worker を保護している Access アプリケーションに、Service Auth ポリシーを追加します。
Worker またはリモートバインディングに使うホスト名をすでに保護している 既存の Access アプリケーションを開き、次の内容の新しいポリシーを付けます。
- Action: Service Auth
- Include: 作成したサービストークン、または任意のサービストークンからのアクセスを許可する場合は "Any Access Service Token"
-
認証情報を Wrangler に渡します。
Wrangler を実行する環境で、
CLOUDFLARE_ACCESS_CLIENT_IDとCLOUDFLARE_ACCESS_CLIENT_SECRETの システム環境変数 を設定します。export CLOUDFLARE_ACCESS_CLIENT_ID=<CLIENT_ID> export CLOUDFLARE_ACCESS_CLIENT_SECRET=<CLIENT_SECRET>CI では値をシークレットとして保存し、Wrangler を実行するステップの環境変数として渡します。
Wrangler は、Miniflare で Worker コードを実行するツール作者向けに、リモートバインディング接続を支えるプログラム用ユーティリティを提供します。
主な API は次のとおりです。
startRemoteProxySession: リモートバインディングとやり取りできるプロキシセッションを開始します。unstable_convertConfigBindingsToStartWorkerBindings: バインディング定義を変換するユーティリティです。experimental_maybeStartOrUpdateProxySession: プロキシセッションの開始または更新を簡単に行う便利関数です。
指定したバインディング集合のプロキシセッションを開始します。セッションの動作を制御するオプションを受け取れます。リモートバインディングへアクセスするための Cloudflare アカウント ID と API トークンを含む auth オプションもあります。
返すオブジェクトは次のとおりです。
readyPromise<void>: セッションの準備ができたときに解決します。dispose() => Promise<void>: セッションを停止します。updateBindings(bindings: StartDevWorkerInput['bindings']) => Promise<void>: セッションのバインディングを更新します。remoteProxyConnectionStringremoteProxyConnectionString: リモートバインディングアクセス用に Miniflare へ渡す文字列です。
unstable_readConfig ユーティリティは、設定ファイルに含まれるバインディング定義を含む Unstable_Config オブジェクトを返します。ただし、これらのバインディング定義は startRemoteProxySession と直接は互換ではありません。unstable_readConfig でバインディング宣言を読み、それを startRemoteProxySession へ渡したい場面は多いです。そのため Wrangler は unstable_convertConfigBindingsToStartWorkerBindings を公開しています。Unstable_Config オブジェクト内のバインディングを、startRemoteProxySession へ渡せる構造へ変換する単純なユーティリティです。
このラッパーは、プロキシセッションの管理を簡単にします。受け取る引数は次のとおりです。
- 次のいずれかを含むオブジェクト
- Wrangler 設定へのパスと、対象になりうる環境
- Worker の名前と、その Worker が使うバインディング
- 現在のプロキシセッションの詳細(ない場合は
null、または省略可) - リモートプロキシセッションに使う認証データ(任意)
開始または更新した場合はプロキシセッションの詳細を返し、プロキシセッションが不要なら null を返します。
関数の動きは次のとおりです。
- 第 1 引数をもとに、プロキシセッション用の入力引数を用意します。
- 使うリモートバインディングがなく(既存のプロキシセッションもない)場合は
nullを返し、プロキシセッションが不要であることを示します。 - 既存のプロキシセッションの詳細が渡されていれば、それに合わせてプロキシセッションを更新します。
- それ以外の場合は、新しいプロキシセッションを開始します。
- プロキシセッションの詳細を返します(あとで
maybeStartOrUpdateRemoteProxySessionの第 2 引数として渡せます)。
Miniflare と maybeStartOrUpdateRemoteProxySession を使い、リモートバインディング付きのローカル開発セッションを提供する基本例です。この例では、ハードコードした KV バインディングを 1 つ使います。
import { Miniflare, MiniflareOptions } from "miniflare";
import { maybeStartOrUpdateRemoteProxySession } from "wrangler";
let mf;
let remoteProxySessionDetails = null;
async function startOrUpdateDevSession() {
remoteProxySessionDetails = await maybeStartOrUpdateRemoteProxySession(
{
bindings: {
MY_KV: {
type: "kv_namespace",
id: "kv-id",
remote: true,
},
},
},
remoteProxySessionDetails,
);
const miniflareOptions = {
scriptPath: "./worker.js",
kvNamespaces: {
MY_KV: {
id: "kv-id",
remoteProxyConnectionString:
remoteProxySessionDetails?.session.remoteProxyConnectionString,
},
},
};
if (!mf) {
mf = new Miniflare(miniflareOptions);
} else {
mf.setOptions(miniflareOptions);
}
}
// ... tool logic that invokes `startOrUpdateDevSession()` ...
// ... once the dev session is no longer needed run
// `remoteProxySessionDetails?.session.dispose()`import { Miniflare, MiniflareOptions } from "miniflare";
import { maybeStartOrUpdateRemoteProxySession } from "wrangler";
let mf: Miniflare | null;
let remoteProxySessionDetails: Awaited<
ReturnType<typeof maybeStartOrUpdateRemoteProxySession>
> | null = null;
async function startOrUpdateDevSession() {
remoteProxySessionDetails = await maybeStartOrUpdateRemoteProxySession(
{
bindings: {
MY_KV: {
type: "kv_namespace",
id: "kv-id",
remote: true,
},
},
},
remoteProxySessionDetails,
);
const miniflareOptions: MiniflareOptions = {
scriptPath: "./worker.js",
kvNamespaces: {
MY_KV: {
id: "kv-id",
remoteProxyConnectionString:
remoteProxySessionDetails?.session.remoteProxyConnectionString,
},
},
};
if (!mf) {
mf = new Miniflare(miniflareOptions);
} else {
mf.setOptions(miniflareOptions);
}
}
// ... tool logic that invokes `startOrUpdateDevSession()` ...
// ... once the dev session is no longer needed run
// `remoteProxySessionDetails?.session.dispose()`Miniflare ベースのローカル開発とは別に、Wrangler は wrangler dev --remote による完全リモートの開発モードも提供します。リモート開発は Vite plugin では 非対応 です。
npx wrangler dev --remoteyarn wrangler dev --remotepnpm wrangler dev --remoteリモート開発 中は、Worker コードはすべて Cloudflare インフラ上の一時的なプレビュー環境へアップロードされ、保存するたびに変更が自動でアップロードされます。
リモート開発では、すべてのバインディングが自動でリモートリソースへ接続します。ローカル開発と違い、バインディングをローカルシミュレーションに切り替えられません。常に Cloudflare ネットワーク上のデプロイ済みリソースを使います。
- ほとんどの開発作業では、ローカル開発に加え、必要なときだけ リモートバインディング を使うのが、いちばん効率的で生産的です。
- Cloudflare のネットワークに強く依存し、ローカルでは十分にシミュレートできず、リモートバインディングでも検証しにくい機能や挙動を試す場合は、
wrangler dev --remoteが向いています。
- 変更のたびにアップロード / デプロイが入るため、反復はローカル開発よりかなり遅くなります。
--remoteフラグでリモート開発セッションを実行すると、ゾーンあたり 50 ルート の制限が適用されます。詳しくは Workers プラットフォームの制限 を参照してください。