Cloudflare Workers KVでAPIを激速化!無料枠で始めるキャッシュ実装手順
TL;DR — 結論から先に
Cloudflare Workers KV をキャッシュ層に挟むだけで、外部APIや重いDB処理のレスポンスタイムを 数百ms → 数十ms に削減できます。無料枠(1日10万リクエスト、1GBストレージ)でも個人開発規模なら十分運用可能。本記事では TypeScript での具体的な実装コードをステップごとに解説します。
Cloudflare Workers KV とは?
KV(Key-Value)ストアはエッジ上に分散配置されたグローバルキャッシュです。Workers から await env.MY_KV.get(key) の1行で読み書きできるシンプルさが魅力。
| 項目 | 無料枠 | Paid ($5/月〜) |
|---|---|---|
| 読み取り | 10万回/日 | 1,000万回/日 |
| 書き込み | 1,000回/日 | 100万回/日 |
| ストレージ | 1GB | 無制限 |
| TTL設定 | ✅ | ✅ |
⚠️ KV は 結果整合性(Eventual Consistency)モデルです。書き込み直後の読み取りで古い値が返るケースがあります。リアルタイム性が必要なデータには不向きなので注意してください。
実装の全体像
クライアント
↓
Cloudflare Workers(エッジ)
├─ KV にキャッシュあり → そのまま返す(超速い)
└─ キャッシュなし → オリジンAPIを叩く → KVに保存 → 返す
TTL(有効期限)を設定しておくことで、古いデータが永遠に返り続けるのを防げます。
ステップ1:KV Namespace を作成・バインドする
CLIで作成
# wrangler がなければ先にインストール
npm install -g wrangler
# KV namespace 作成
npx wrangler kv:namespace create "API_CACHE"
実行すると以下のような出力が得られます:
Add the following to your configuration file in your kv_namespaces array:
{ binding = "API_CACHE", id = "xxxxxxxxxxxxxxxxxxxxxxxxxx" }
wrangler.toml に追記
name = "my-api-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[kv_namespaces]]
binding = "API_CACHE"
id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
TypeScript の型定義
// src/types.ts
export interface Env {
API_CACHE: KVNamespace;
}
ステップ2:キャッシュユーティリティ関数を実装する
再利用しやすいように、KVラッパーを共通関数として切り出します。
// src/cache.ts
import type { Env } from "./types";
/**
* KV キャッシュ付きフェッチ
* @param key KV のキー(URLなど一意な文字列)
* @param fetcher キャッシュミス時に実行する非同期関数
* @param ttl キャッシュ有効期限(秒)デフォルト60秒
*/
export async function cachedFetch<T>(
env: Env,
key: string,
fetcher: () => Promise<T>,
ttl = 60
): Promise<T> {
// 1. キャッシュを確認
const cached = await env.API_CACHE.get(key, { type: "json" });
if (cached !== null) {
console.log(`[CACHE HIT] ${key}`);
return cached as T;
}
// 2. キャッシュミス → オリジンから取得
console.log(`[CACHE MISS] ${key}`);
const data = await fetcher();
// 3. KV に保存(TTL 付き)
await env.API_CACHE.put(key, JSON.stringify(data), {
expirationTtl: ttl,
});
return data;
}
ポイントは { type: "json" } オプションを使うことで、JSON.parse を自分で書かずに済む点です。
ステップ3:Workers のエントリポイントで使う
// src/index.ts
import type { Env } from "./types";
import { cachedFetch } from "./cache";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// /api/posts に来たリクエストを例にキャッシュする
if (url.pathname === "/api/posts") {
const posts = await cachedFetch(
env,
"posts:all", // KVキー
async () => {
// 外部API(例: JSONPlaceholder)を叩く
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
return res.json();
},
300 // 5分キャッシュ
);
return Response.json(posts, {
headers: {
// クライアントにもキャッシュ状態を通知(任意)
"X-Cache": "HIT-OR-MISS",
},
});
}
return new Response("Not Found", { status: 404 });
},
};
ステップ4:キャッシュの強制削除(パージ)を実装する
データ更新時に古いキャッシュを即時削除したいケースに対応します。
// 管理用エンドポイント(Secret ヘッダーで保護)
if (url.pathname === "/admin/cache/purge" && request.method === "DELETE") {
const secret = request.headers.get("X-Admin-Secret");
if (secret !== env.ADMIN_SECRET) {
return new Response("Unauthorized", { status: 401 });
}
const key = url.searchParams.get("key") ?? "";
await env.API_CACHE.delete(key);
return Response.json({ purged: key });
}
wrangler.toml に ADMIN_SECRET を秘密変数として登録しておきましょう:
npx wrangler secret put ADMIN_SECRET
ステップ5:ローカルで動作確認してデプロイ
# ローカル起動(KVもローカルエミュレーション)
npx wrangler dev
# 本番デプロイ
npx wrangler deploy
wrangler dev はデフォルトで KV をローカルの SQLite にエミュレートしてくれるので、実際に手元でキャッシュヒット/ミスの挙動を確認できます。
キャッシュキーの設計ベストプラクティス
個人開発で後悔しないキー設計のコツをまとめます。
| パターン | キー例 | 説明 |
|---|---|---|
| リソース単位 | posts:all | 一覧データ |
| ID 単位 | post:42 | 個別リソース |
| ユーザー別 | user:${userId}:feed | パーソナライズデータ |
| クエリ付き | search:${encodeURIComponent(q)} | 検索結果 |
- キー名は プレフィックス:識別子 の形式にすると管理しやすい
- ユーザーごとにキャッシュすると書き込み数が爆増する可能性があるので、無料枠では注意
- 機密情報(トークンなど)をキーに含めない
実測パフォーマンス比較
実際に JSONPlaceholder(外部API)を叩くケースで計測した参考値です:
| 条件 | レスポンスタイム |
|---|---|
| キャッシュなし(毎回外部API) | 280〜450ms |
| KV キャッシュヒット時 | 8〜25ms |
エッジノードに KV のレプリカが配置されているため、ヒット時は驚異的な速度が出ます。体感差は非常に大きいです。
まとめ
Cloudflare Workers KV をキャッシュ層に使う実装のポイントを整理します。
wrangler kv:namespace createで Namespace を作りwrangler.tomlにバインドcachedFetchユーティリティを共通化して使い回す- TTL を適切に設定して古いデータが残らないようにする
- パージエンドポイントを用意しておくとデータ更新時に便利
- 無料枠の 書き込み1,000回/日 制限に注意し、更新頻度の低いデータに絞って使う
無料枠の制限内で賢く使えば、個人開発のAPIを外部コストゼロで大幅に高速化できます。まずは読み取りが多い静的寄りのエンドポイントから試してみるのがおすすめです。
Cloudflare のエッジネットワークを活かしたサーバーレス開発に興味が出てきたら、VPSでの自前サーバー運用と組み合わせる構成も面白いです。