Advanced (更新: 2026/6/2)

Claude Codeでエッジコンピューティングを活用する

Claude CodeでEdge runtimeを設計。Workers、地域分岐、キャッシュ、検証コマンドまで実例で解説。

Claude Codeでエッジコンピューティングを活用する

エッジコンピューティングは「利用者に近い場所で小さな処理を済ませる設計」です。東京の読者には近い拠点、米国の読者には米国側の拠点で、リダイレクト、キャッシュ、軽い認証、A/Bテストの割り当てを処理できます。

ただし、Edge runtimeは速い魔法ではありません。Node.jsの通常サーバーと違い、使えるAPI、実行時間、パッケージ、キャッシュの効き方に制約があります。Claude Codeに「エッジ対応して」とだけ頼むと、fscryptoなどのNode専用APIを混ぜたり、地域ごとのキャッシュキーを忘れたりします。

この記事では、2026年6月2日時点の公式情報を前提に、Claude Codeへ渡す要件、Cloudflare Workersのコピペ可能な実装、Vercel Edge Middlewareの小さな例、Deno Deployへ移すときの考え方、検証コマンドまでまとめます。公式情報はCloudflare WorkersWorkers Request APICache APIVercel Edge RuntimeDeno Deploy runtimeClaude Code overviewを確認してください。Cloudflare単独の実装はClaude CodeでCloudflare Workersを実装する実践ガイド、Vercel単独の注意点はClaude CodeでVercel Edge Functionsを安全に使う実務ガイドも参考になります。

Edgeに置く処理を先に決める

初心者が最初に迷うのは「何をEdgeに置くか」です。目安は、リクエストのURL、ヘッダー、Cookie、短い本文だけで判断できる処理です。逆に、DBを深く読む処理、重いLLM呼び出し、画像変換、長いバッチ処理、課金確定処理は、通常のサーバーやキューに残すほうが安全です。

ユースケースEdgeに置く理由残すべき処理
地域別の表示切り替え国コードや言語ヘッダーで入口をすぐ分けられる税金計算、請求、在庫確定
短時間キャッシュAPIレスポンスを近い拠点で返せるDB更新、再生成ジョブ
A/Bテストの割り当てCookieを見てページ到達前に分岐できる統計判定、売上分析
軽い認証ゲート管理画面やプレビューを早い段階で止められるセッション発行、権限監査
Webhookの入口検証署名だけ確認して内部APIへ渡せる決済処理、メール送信、リトライ

この表をClaude Codeへの依頼に入れると、出力がかなり安定します。「Edgeに置くもの」と「Edgeに置かないもの」を分けるだけで、無理な最適化や危ない秘密情報の混入を減らせます。

flowchart LR
  User["User request"] --> Edge["Edge runtime"]
  Edge --> Geo["Country / language branch"]
  Edge --> Cache["Short cache"]
  Edge --> Gate["Light auth gate"]
  Edge --> Origin["Origin API / database"]
  Origin --> Queue["Queue or background work"]

Claude Codeに渡す最初のプロンプト

Edge実装では、プロンプトに「速くして」ではなく「どの制約を守るか」を入れます。Claude Codeはコードを速く出せますが、キャッシュキー、地域分岐、秘密情報、検証コマンドは明示しないと抜けやすいです。

Cloudflare Workers + TypeScriptでEdge runtimeの小さなAPIを実装してください。

変更対象:
- wrangler.toml
- src/index.ts

要件:
- GET /health はJSONを返す
- GET /api/edge-content は国コードに応じてlocaleとCTA文言を返す
- Cloudflareのrequest.cf.countryがあれば使い、ローカル検証ではCF-IPCountryヘッダーも使えるようにする
- Cache APIでlocale別に60秒キャッシュする
- cache hit/missをX-Edge-Cacheヘッダーで返す
- Node.js専用APIは使わず、Web標準のRequest/Response/URL/cryptoだけで書く
- curlで確認できる検証コマンドを3つ以上添える

禁止:
- 疑似コードで済ませる
- API tokenやsecretをコードへ直書きする
- 国コードだけで課金や権限を確定する

専門用語も先に言い換えておきます。runtimeは「コードが実行される環境」、cache keyは「キャッシュを取り出すための名前」、coloはCloudflareのデータセンター識別子です。Claude Codeにこの言い換えを渡すと、初心者向けドキュメントやレビューコメントも読みやすくなります。

Cloudflare Workersの実装例

次の例は、Cloudflare Workersでそのまま試せる小さなAPIです。/api/edge-contentへアクセスすると、国コードからロケールを決め、同じロケールとパスのレスポンスを60秒だけCache APIへ保存します。ローカルではCF-IPCountryヘッダーをcurlで渡せるので、地域分岐を手元で確認できます。

name = "claude-edge-router"
main = "src/index.ts"
compatibility_date = "2026-06-02"

[vars]
DEFAULT_LOCALE = "en"
// src/index.ts
export interface Env {
  DEFAULT_LOCALE: string;
}

type Locale = "ja" | "en" | "zh" | "ko" | "es" | "fr" | "de" | "pt" | "hi" | "id";

type CfRequest = Request & {
  cf?: {
    country?: string;
    colo?: string;
    city?: string;
  };
};

const SUPPORTED_LOCALES = new Set<Locale>([
  "ja",
  "en",
  "zh",
  "ko",
  "es",
  "fr",
  "de",
  "pt",
  "hi",
  "id",
]);

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === "/health") {
      return json({ ok: true, runtime: "cloudflare-workers" });
    }

    if (url.pathname === "/api/edge-content") {
      return handleEdgeContent(request, env, ctx);
    }

    return json({ error: "not_found" }, 404);
  },
} satisfies ExportedHandler<Env>;

async function handleEdgeContent(
  request: Request,
  env: Env,
  ctx: ExecutionContext
): Promise<Response> {
  const url = new URL(request.url);
  const country = getCountry(request);
  const locale = localeFromCountry(country, env.DEFAULT_LOCALE);
  const cacheKey = buildCacheKey(request, locale);
  const cached = await caches.default.match(cacheKey);

  if (cached) {
    return withHeaders(cached, {
      "X-Edge-Cache": "HIT",
      "X-Edge-Locale": locale,
    });
  }

  const body = {
    locale,
    country,
    colo: getColo(request),
    path: url.pathname,
    cta: localizedCta(locale),
    generatedAt: new Date().toISOString(),
  };

  const response = json(body, 200, {
    "Cache-Control": "public, max-age=0, s-maxage=60, stale-while-revalidate=300",
    "X-Edge-Cache": "MISS",
    "X-Edge-Locale": locale,
  });

  ctx.waitUntil(caches.default.put(cacheKey, response.clone()));
  return response;
}

function buildCacheKey(request: Request, locale: Locale): Request {
  const url = new URL(request.url);
  url.search = "";
  url.pathname = `/__edge-cache/${locale}${url.pathname}`;
  return new Request(url.toString(), { method: "GET" });
}

function getCountry(request: Request): string {
  const cf = (request as CfRequest).cf;
  return (
    request.headers.get("CF-IPCountry") ||
    request.headers.get("x-country") ||
    cf?.country ||
    "US"
  ).toUpperCase();
}

function getColo(request: Request): string {
  return (request as CfRequest).cf?.colo || "local";
}

function localeFromCountry(country: string, fallback: string): Locale {
  const normalizedFallback = SUPPORTED_LOCALES.has(fallback as Locale)
    ? (fallback as Locale)
    : "en";

  switch (country) {
    case "JP":
      return "ja";
    case "CN":
    case "TW":
    case "HK":
      return "zh";
    case "KR":
      return "ko";
    case "ES":
    case "MX":
    case "AR":
      return "es";
    case "FR":
      return "fr";
    case "DE":
      return "de";
    case "BR":
    case "PT":
      return "pt";
    case "IN":
      return "hi";
    case "ID":
      return "id";
    default:
      return normalizedFallback;
  }
}

function localizedCta(locale: Locale): string {
  const messages: Record<Locale, string> = {
    ja: "Claude Code教材を見る",
    en: "Explore Claude Code templates",
    zh: "查看 Claude Code 教材",
    ko: "Claude Code 템플릿 보기",
    es: "Ver plantillas de Claude Code",
    fr: "Voir les modèles Claude Code",
    de: "Claude Code Vorlagen ansehen",
    pt: "Ver modelos de Claude Code",
    hi: "Claude Code टेम्पलेट देखें",
    id: "Lihat template Claude Code",
  };
  return messages[locale];
}

function json(data: unknown, status = 200, headers: HeadersInit = {}): Response {
  return new Response(JSON.stringify(data, null, 2), {
    status,
    headers: {
      "Content-Type": "application/json; charset=utf-8",
      "X-Content-Type-Options": "nosniff",
      ...headers,
    },
  });
}

function withHeaders(response: Response, headers: Record<string, string>): Response {
  const next = new Response(response.body, response);
  for (const [key, value] of Object.entries(headers)) {
    next.headers.set(key, value);
  }
  return next;
}

このコードのポイントは、キャッシュキーにlocaleを入れていることです。ここを省くと、日本向けのCTAが米国ユーザーにも返るような事故が起きます。また、国コードは体験の出し分けには使えますが、本人確認、課金、法務判断の根拠にはしないでください。VPN、企業プロキシ、CDNの設定で変わることがあります。

Vercel EdgeとDeno Deployへ広げる

Vercel Edge Middlewareでは、ページへ届く前にCookieやヘッダーを整えられます。Vercelでは公式ドキュメントのEdge Runtime制約を確認し、Node.js専用パッケージを入れないことが重要です。

// middleware.ts
import { NextRequest, NextResponse } from "next/server";

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

export function middleware(request: NextRequest) {
  const country = request.headers.get("x-vercel-ip-country") || "US";
  const bucket = request.cookies.get("edge_bucket")?.value || chooseBucket();
  const response = NextResponse.next();

  response.headers.set("x-edge-country", country);
  response.headers.set("x-edge-bucket", bucket);
  response.cookies.set("edge_bucket", bucket, {
    maxAge: 60 * 60 * 24 * 30,
    sameSite: "lax",
    secure: true,
  });

  if (country === "JP" && request.nextUrl.pathname === "/pricing") {
    return NextResponse.redirect(new URL("/jp/pricing", request.url));
  }

  return response;
}

function chooseBucket(): "a" | "b" {
  const bytes = new Uint8Array(1);
  crypto.getRandomValues(bytes);
  return bytes[0] < 128 ? "a" : "b";
}

Deno Deployへ寄せる場合も、基本はWeb標準APIのRequestResponseで小さく書きます。プラットフォームごとのヘッダーや環境変数は違うので、Claude Codeには「Cloudflare専用のrequest.cfをDenoへそのまま持ち込まない」と伝えます。

// main.ts
Deno.serve((request: Request) => {
  const url = new URL(request.url);
  const country = request.headers.get("x-country") || "US";

  if (url.pathname !== "/api/edge-content") {
    return Response.json({ error: "not_found" }, { status: 404 });
  }

  return Response.json({
    runtime: "deno-deploy",
    country,
    message: country === "JP" ? "日本向けの入口です" : "Default edge entry",
  });
});

検証コマンド

Edge実装は、本番に出す前に「型」「ローカルHTTP」「地域分岐」「キャッシュ」「デプロイ前の設定」を確認します。Claude Codeにも、実装後にこの証拠を残すよう依頼してください。

npm create cloudflare@latest claude-edge-router -- --type=hello-world
cd claude-edge-router
npm install -D typescript wrangler
npx wrangler types
npx tsc --noEmit
npx wrangler dev

別ターミナルでcurlを実行します。

curl -i http://127.0.0.1:8787/health
curl -i -H "CF-IPCountry: JP" http://127.0.0.1:8787/api/edge-content
curl -i -H "CF-IPCountry: US" http://127.0.0.1:8787/api/edge-content
curl -i -H "CF-IPCountry: JP" "http://127.0.0.1:8787/api/edge-content?utm_source=test"
npx wrangler deploy --dry-run

期待する見方は単純です。1回目はX-Edge-Cache: MISS、同じロケールとパスの2回目はHITになります。JPではlocaleja、USではenになります。utm_sourceを消したキャッシュキーにしているため、不要な広告パラメータでキャッシュが割れません。

よくある落とし穴

1つ目は、Edgeに重い処理を載せすぎることです。LLMへの長い問い合わせ、ORMを使った複雑なDB処理、PDF生成、画像変換をEdgeへ寄せると、速くなるどころか制約で詰まります。入口の判断だけEdgeに置き、重い処理は通常のAPIやキューに渡します。

2つ目は、キャッシュキーが粗いことです。国、ロケール、ログイン状態、価格表示、実験バケットが違うのに同じキーで保存すると、別ユーザー向けの内容が混ざります。逆に、utm_*や不要なタイムスタンプまでキーに入れると、キャッシュがほぼ効きません。

3つ目は、地域情報を信頼しすぎることです。request.cf.countryx-vercel-ip-countryは便利ですが、請求、税金、権限、年齢確認を確定する根拠にはなりません。地域別の文言や初期表示に使い、重要な判断は認証済みユーザー情報やサーバー側の確定データで行います。

4つ目は、Claude Codeへプラットフォーム名だけを渡すことです。「Workersで作って」だけでは、Cache APIを使うのかKVを使うのか、D1へ行くのか、Vercelへ移植するのかが曖昧です。内部リンクとしてサーバーレス関数ガイドパフォーマンス最適化も合わせて読むと、Edgeと通常サーバーの境界を決めやすくなります。

収益導線と次の行動

Edge runtimeは、ClaudeCodeLabのような多言語コンテンツサイトでも収益導線に効きます。国別に無料PDFの案内文を変える、教材CTAを近い言語へ出す、広告計測の不要なパラメータを正規化する、といった小さな改善はEdgeと相性が良いです。

実装テンプレートを手元に置きたい場合はClaudeCodeLabの商品一覧を確認してください。チームでClaude Codeの依頼文、レビュー観点、Edge/Nodeの境界を整えたい場合はClaude Code研修・導入相談が向いています。無料で流れを確認したい場合は無料チートシートから始めると、プロンプトと検証コマンドをセットで見直せます。

実際に試した結果

この記事の更新では、MasaがローカルのWorkersサンプルでCF-IPCountry: JPCF-IPCountry: USを切り替え、localeX-Edge-Cache、広告パラメータを外したキャッシュキーの挙動を確認しました。検証中に分かったのは、ローカルではテスト用ヘッダーをrequest.cf.countryより先に読む順序にしないと、国コードの切り替え確認がぶれることです。さらに、キャッシュキーは/__edge-cache/${locale}${pathname}の形にして、地域分岐とキャッシュが混ざらないようにしました。Claude Codeに依頼する時点で「ヘッダー優先順、地域分岐、キャッシュキーを同時にレビューして」と書くと、この手戻りはかなり減らせます。

まとめ

エッジコンピューティングは、全部をEdgeに移す話ではありません。入口で判断できる処理だけを近い場所へ置き、重い処理や確定判断は通常のAPIに残す設計です。Claude Codeには、Edge runtimeの制約、キャッシュキー、地域分岐、検証コマンドをまとめて渡してください。そこまで具体化すれば、速いだけでなくレビューしやすいEdge実装になります。

#Claude Code #エッジコンピューティング #Cloudflare Workers #Vercel #パフォーマンス
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。