この記事は ひとりCloudflareを使い倒す Advent Calendar 2025 の4日目です
どうも、とれいすあっぷと申します。
4日目は「Cloudflareを使い倒す Workers編」ということで、この記事からついに、ちゃんと製品を触っていきます。
この記事では、いつもなんとなくで使っている Cloudflare Workers について、調べて、触って見ます。
Cloudflare Workers って、何。
公式ドキュメントを読みます。
A serverless platform for building, deploying, and scaling apps across Cloudflare's global network with a single command — no infrastructure to manage, no complex configuration
Cloudflare のグローバルネットワークをまたがるアプリケーションを、たった一つのコマンドでビルド、デプロイ、そしてスケーリングするサーバレスプラットフォーム。
管理するインフラも無ければ、複雑なコンフィグもありません。(筆者訳)
私がわかるように言い換えますと、
- 世界にまたがる Cloudflare network (データセンター) へアプリが置ける
- 勝手にアプリケーションをビルドして、デプロイして、スケーリングしてくれる
- VPS とか借りなくていい (= インフラ管理が必要ない)
- ランタイムのバージョン構成とかも考えなくていい (= 複雑なコンフィグがいらない)
ということですね。
Cloudflare 公式が、Workers を使うと何が期待できるのか書いていました。
With Cloudflare Workers, you can expect to:
- Deliver fast performance with high reliability anywhere in the world
- Build full-stack apps with your framework of choice, including React, Vue, Svelte, Next, Astro, React Router, and more
- Use your preferred language, including JavaScript, TypeScript, Python, Rust, and more
- Gain deep visibility and insight with built-in observability
- Get started for free and grow with flexible pricing, affordable at any scale
これも私がわかるようにまとめますと
- 世界中のどこにいても、高性能かつ高い信頼性のアプリを使えるようになる
- フルスタック (React, Next, Vue, Nuxt, Svelte, Astro など…) を置ける
- JavaScript, TypeScript, Python, Rustとかで書いたアプリが動く
- ビルトインの機能でログやエラーなど、様々な指標が見られる
- タダで使える!
「タダでいろんなフルスタックアプリが動いて激アツ」ということがわかりました。
上から 3 つめの「どんな言語でも動くっぽい?」というのは、実際にはなんでも動くわけではないようです。
仕組みのところで詳しく見ていきますが、Workers を動かしている V8 ランタイムで実行できる JS, WASM に限定されています。
Workers の仕組み
いろんなアプリが動いて激アツなのはわかりましたが、どうやって動いているのでしょうか?
やっぱり、ドキュメントを見ていきましょう。
サーバーレスコードの実行場所:全地球
かっこいいですね。
こういうアプリケーションなら、他のアプリケーションとの兼ね合いを考えれば、コンテナが動いていそうです。
しかし、コンテナを起こして、コードを読んで…ってやっていると、世界からのリクエストには間に合わないですよね。
(AWS Lambda はそういう動作をしますが…)
そこで、JSエンジンの V8 です。
V8 は Google Chrome もとい Chromium 系のブラウザや、Node.js にも採用されている JavaScript エンジンです。
V8 には "Isolate" と呼ばれる、いわば JavaScript 専用の仮想環境みたいな仕組みが備わっています。
そして、V8 たった 1 つで大量に Isolate を生成できます。
Isolate 自体は、それぞれの Isolate から他の Isolate にちょっかいを出せない安全仕様になっています。
コンテクストスイッチングもほぼ存在せず、大量に並列実行しても大きく遅延することはありません。
この安全にできて、高速に大量という恩恵を受けるために、Cloudflare Workers のランタイムは V8 エンジンを使って作られています。
数千のアプリケーションをホストしたとしても Isolate を管理するランタイム自体は 1 つなので、アプリが建てられないメモリ (= アプリ以外に割り当てるメモリ) はランタイム 1 つ分で済むのです。

Cloudflare Workers のリソース使用のイメージ
(https://www.cloudflare.com/ja-jp/developer-platform/products/workers/ より引用した画像)
話を戻しまして、Cloudflare Workers は V8 エンジンの上で動いているというお話でした。
V8 は JS エンジンであるとともに、WebAssembly も動くエンジンです。
詳細は他の記事を参照いただきたいですが、WebAssembly はいろんな言語で書いたものをコンパイルして WebAssemblyにするので、例えば C, C++, C#, Rust, Go, Kotlin, etc...で書いたコードも WebAssembly になります。
つまり、V8 で動かせて怪しくないアプリなら何でも Workers で動かせるのです。やったぁ!
といった具合で、V8 を乗っけた Cloudflare Workers Runtime が全世界にある Cloudflare のデータセンターに乗っかっているのです。
そして世界の誰かがアプリケーションにアクセスすると、その人に一番近いデータセンターが Workers でアプリケーションを走らせて、素早く結果を返してくれているわけですね。
外部サービスにつながる Workers が無敵すぎる件
Cloudflare Workers は env オブジェクトの Bindings を通して、Cloudflare が持っている他の製品にアクセスできます。
一例として AI, D1 (Database), KV (Key-Value Store) などがあります。
ここらへんは今後扱っていくので、今は「Cloudflare 製品は Workers アプリケーションとして使えるんだなあ」と思ってもらえると良いと思います。
気になる方は是非、以下のページから。
Workers を使ってみる
さて、知識のインプットは終わりです。Workers を使ってみましょう。
どうせ今後出す記事のほとんどで Bindings を使っていきますので、今回はシンプルに Workers だけを使ってみましょう。
ここから先は、Cloudflare のアカウントを持っていることを前提とします。
作ってないよ、という方はこちらから手順に沿って作成してください。
ここでは、Tutorial の A/B テストを実装してみます。
A/B テストがなにか、って話は割愛しますが、ゴールは
- あるリンクにアクセスしたとき、自動的に 2 つあるウェブページのどちらかを表示する
- 一度表示するページが決まったら、Cookie ベースでずっとその表示先を表示する
とします。
開発環境
- node v24.11.1
- npm v11.6.2
- pnpm v10.22.0
※これ以降、プロジェクト自体はこのページに沿って作っていきます。
1. Worker Project を作る
まずは適当にディレクトリを作ります。
そして、そのディレクトリの中で、Cloudflare Workers Project を作ります。
cf-use-up-worker-basic> pnpm create cloudflare@latest .
──────────────────────────────────────────────────────────────────────────────────────────────────────────
👋 Welcome to create-cloudflare v2.54.5!
🧡 Let's get started.
📊 Cloudflare collects telemetry about your usage of Create-Cloudflare.
Learn more at: https://github.com/cloudflare/workers-sdk/blob/main/packages/create-cloudflare/telemetry.md
──────────────────────────────────────────────────────────────────────────────────────────────────────────
╭ Create an application with Cloudflare Step 1 of 3
│
├ In which directory do you want to create your application?
│ dir ./.
│
╰ What would you like to start with?
● Hello World example
○ Framework Starter
○ Application Starter
○ Template from a GitHub repo
◁ Go back
Select from barebones examples to get started with Workers
ここで、Hello World example のままエンターキーを押します。
╰ Which template would you like to use?
○ Worker only
○ Static site
● SSR / full-stack app
○ Worker + Durable Objects
○ Worker + Durable Objects + Assets
○ Workflow
○ Scheduled Worker (Cron Trigger)
○ Queue consumer & producer Worker
○ API starter (OpenAPI compliant)
◁ Go back
--(上矢印2回押すと)----------------
For sites with a backend API, or server-side rendering (SSR). Uses Static Assets with a Worker.
╰ Which template would you like to use?
● Worker only
○ Static site
○ SSR / full-stack app
○ Worker + Durable Objects
○ Worker + Durable Objects + Assets
○ Workflow
○ Scheduled Worker (Cron Trigger)
○ Queue consumer & producer Worker
○ API starter (OpenAPI compliant)
◁ Go back
For sites with a backend API, or server-side rendering (SSR). Uses Static Assets with a Worker.
テンプレート、何使う?って聞いてくれるので、上矢印を 2 回押して Worker only を選択し、エンターキーを押します。
╰ Which language do you want to use?
● TypeScript
○ JavaScript
○ Python (beta)
◁ Go back
実装言語を聞いてきますので、TypeScript のままエンターキーを押します。
ブワーッと初期化をしてくれるので、お茶
を啜って待ちます。
したらば、
╰ You're in an existing git repository. Do you want to use git for version control?
Yes / No
git で管理しますか?って聞いてくるので、好きに選択していただき、
╭ Deploy with Cloudflare Step 3 of 3
│
╰ Do you want to deploy your application?
Yes / No
Deploy しますか?って聞いてくるので、一旦 No を選択しておきます。
これでプロジェクトのセットアップは終わりです。
2. コードを書く
を参考に、コードを書いていきます。
const NAME = 'myExampleABTest';
export default {
async fetch(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname.endsWith('.ico'))
return new Response(null, { status: 404 });
if (url.pathname.startsWith('/a') || url.pathname.startsWith('/b')) {
return fetch(req)
}
const cookie = req.headers.get('cookie');
if (cookie && cookie.includes(`${NAME}=a`)) {
url.pathname = '/a' + url.pathname;
} else if (cookie && cookie.includes(`${NAME}=b`)) {
url.pathname = '/b' + url.pathname;
} else {
const group = Math.random() < 0.5 ? 'a' : 'b';
if (group === 'a') {
url.pathname = '/a' + url.pathname;
} else {
url.pathname = '/b' + url.pathname;
}
let res = await fetch(url);
res = new Response(res.body, res);
res.headers.set('Set-Cookie', `${NAME}=${group}; path=/;`);
return res;
}
return fetch(url);
},
} satisfies ExportedHandler;
元のコードから変更したところといえば
- A/B をわかりやすくした
- favicon.ico を 404 で返すようにした
くらいです。
コードの解説ですが、今回のケースでは、/ にアクセスしたら Cookie を見に行きます。
Cookie が書き込まれていたら、取ってくる html の path を a か b に切り替えます。
Cookie がなければ、新しくアクセスしてきたと判断して、乱数で a か b を設定し、path を a か b に切り替えます。
で、Workers から切り替えた path に向かってリクエストを飛ばして、取ってきた html をブラウザに返します。
起動してみましょう!
> pnpm run dev
⛅️ wrangler 4.47.0
───────────────────
╭──────────────────────────────────────────────────────────────────────╮
│ [b] open a browser [d] open devtools [c] clear console [x] to exit │
╰──────────────────────────────────────────────────────────────────────╯
⎔ Starting local server...
[wrangler:info] Ready on http://127.0.0.1:8787
サーバーが動きました。
ブラウザで http://127.0.0.1:8787 を開きます。
………開きません。
待てど暮らせど、開きませんね。
Cloudflare Workers はページリンクをもらっていますが、肝心のリンク先がないのです。
ということで、一旦 Ctrl + C で止めましょう。
肝心の html も Workers から返せるようにする
html を静的リソースとして、Workers にもたせることができます。
ということで、まずは assets ディレクトリを切ります。
そして、2 つ html ファイルを書きます。
<html>
<head>
<title>Page A</title>
</head>
<body>
<h1>Welcome to Page A</h1>
<p>This is the A version of the A/B test.</p>
</body>
</html>
<html>
<head>
<title>Page B</title>
</head>
<body>
<h1>Welcome to Page B</h1>
<p>This is the B version of the A/B test.</p>
</body>
</html>
そして、wrangler.jsonc をいじって、html ファイルを返せるようにします。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "cf-use-up-worker-basic-ab-testing",
"main": "src/index.ts",
"compatibility_date": "2025-11-15",
"observability": {
"enabled": true
},
"assets": { "directory": "./assets/", "binding": "ASSETS" }
}
これで、Workers が html ファイルを返してくれるようになります。
そして、pnpm dlx wrangler types で env の型定義を更新します。
で、デプロイできるようにコードを修正します。(詳細は省略)
const NAME = 'myExampleABTest';
export default {
- async fetch(req: Request): Promise<Response> {
+ async fetch(req: Request, env: Env): Promise<Response> {
const url = new URL(req.url);
if (url.pathname.endsWith('.ico'))
return new Response(null, { status: 404 });
if (url.pathname.startsWith('/a') || url.pathname.startsWith('/b')) {
- return fetch(req)
+ return env.ASSETS.fetch(req)
}
const cookie = req.headers.get('cookie');
if (cookie && cookie.includes(`${NAME}=a`)) {
url.pathname = '/a' + url.pathname;
} else if (cookie && cookie.includes(`${NAME}=b`)) {
url.pathname = '/b' + url.pathname;
} else {
const group = Math.random() < 0.5 ? 'a' : 'b';
if (group === 'a') {
url.pathname = '/a' + url.pathname;
} else {
url.pathname = '/b' + url.pathname;
}
- let res = await fetch(url);
+ let res = await env.ASSETS.fetch(url);
res = new Response(res.body, res);
res.headers.set('Set-Cookie', `${NAME}=${group}; path=/;`);
return res;
}
- return fetch(req)
+ return env.ASSETS.fetch(req)
},
- } satisfies ExportedHandler;
+ } satisfies ExportedHandler<Env>;
早速 pnpm run dev で実行して、http://127.0.0.1:8787 にアクセスしてみましょう。
Page A が表示されました!(この画面は人により異なります。)
開発者モードを開いて、Cookie を見てみますと
値が a になっていることが確認できました。
(Page B が見えていたら b になっているはずです。)
ここの値を a から b (b なら a) にしてみましょう。
そしてリロードしてみますと、
Page B になりました。
Cookie を消してみましょう。
50% の確率で Page B が Page A になります。
私はなりませんでした。
なった皆さんは、明日なくした靴下の片方が見つかります。おめでとうございます。
3. デプロイ
動くことがわかりましたので、Cloudflare の世界ネットワークに乗っけてみます。
wrangler login で、Wrangler にデプロイするアカウントを教えます。
> pnpm dlx wrangler login
すると、勝手にブラウザが開いて、ログインを要求されます。
で、リダイレクトしますので、内容を読んで、許可します。
閉じていいよ!って出ますので、閉じます。
そしたら、いよいよデプロイです。
> pnpm dlx wrangler deploy
実行するだけで、うにゃうにゃしてくれます。
⛅️ wrangler 4.47.0
───────────────────
🌀 Building list of assets...
✨ Read 2 files from the assets directory hogehoge\assets
🌀 Starting asset upload...
No updated asset files to upload. Proceeding with deployment...
Total Upload: 1.03 KiB / gzip: 0.46 KiB
Your Worker has access to the following bindings:
Binding Resource
env.ASSETS Assets
Uploaded hogehoge (5.22 sec)
Deployed hogehoge (1.35 sec)
https://hogehoge.yourname.workers.dev
Current Version ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Deployed の下にある workers.dev のリンクにアクセスしてみましょう。
Cloudflare に乗っかった A/B テストの完成です。
まとめ
Cloudflare Workers について、ざっくりとした概要、そして仕組みをまとめました。
そして、実際に A/B テストを作ってみて、デプロイまでこぎつけました。
Cloudflare Workers はいくらでも便利な使い方ができそうです。
▼ 一覧
ぜひ、いろんなことをやってみてください。
Cloudflare ことはじめとして、参考になれば幸いです。
Appendix
この記事を書くうえで参考にしたドキュメントです。ぜひ読んでみてください。
Cloudflare Workers が出来上がった背景
V8 について






