Use Cases (Aktualisiert: 3.6.2026)

Cloudflare Workers mit Claude Code: Praxisguide für Edge APIs

Baue eine Workers API mit Claude Code, Wrangler, KV/D1/R2, Cache, Rate Limiting, Logs und Security Headers.

Cloudflare Workers mit Claude Code: Praxisguide für Edge APIs

Cloudflare Workers führt JavaScript und TypeScript im Edge-Netzwerk von Cloudflare aus. Edge bedeutet: Der Code läuft näher am Nutzer statt nur in einer zentralen Region. Das passt gut für kleine APIs, Webhooks, BFFs, gecachte Antworten, Sicherheitsprüfungen und kontrollierte Downloads aus R2.

Claude Code ist dafür nützlich, weil ein Worker sauber zerfällt: ein fetch Handler, eine wrangler.toml und explizite Bindings wie KV, D1 und R2. Die offiziellen Quellen wurden am 3. Juni 2026 erneut geprüft: Workers, Wrangler, bindings, KV, D1, R2, Cache API, Rate Limiting und Workers Logs. Für den Vergleich helfen serverless functions und der AWS Lambda guide.

Was wir bauen

Das Beispiel ist eine Orders API. D1 speichert Bestellungen, KV hält kleine Einstellungen, R2 speichert Receipt JSON, Cache API beschleunigt sichere GET-Antworten, Rate Limiting bremst Missbrauch, Workers Logs erfassen strukturierte Logs und jede Antwort bekommt Security Headers.

flowchart LR
  Client["Client"] --> Worker["Worker fetch handler"]
  Worker --> D1["D1 orders"]
  Worker --> KV["KV settings"]
  Worker --> R2["R2 receipts"]
  Worker --> Cache["Cache API"]
  Worker --> Logs["Workers Logs"]

Ein Binding ist eine externe Fähigkeit, die dem Worker unter einem Namen bereitgestellt wird. binding = "DB" wird im Code zu env.DB.

Prompt für Claude Code

Implementiere eine Orders API mit Cloudflare Workers + TypeScript.

Dateien:
- src/index.ts
- wrangler.toml
- schema.sql

Anforderungen:
- Module fetch handler verwenden
- GET /health gibt JSON zurück
- GET /orders/:id liest aus D1 und cached nur sichere öffentliche Ausgabe 30 Sekunden
- POST /orders validiert JSON und schreibt in D1
- Authorization Bearer gegen API_TOKEN prüfen
- SETTINGS KV, DB D1, RECEIPTS R2 und API_RATE_LIMITER verwenden
- Security Headers für jede Antwort setzen
- Logs als JSON Objekte ausgeben
- curl Prüfkommandos ergänzen

Nicht tun:
- Secrets in wrangler.toml schreiben
- Einen dauerhaft laufenden Node.js Server voraussetzen
- Pseudocode liefern

Wrangler Setup

npm create cloudflare@latest claude-worker-api -- --type=hello-world
cd claude-worker-api
npm install -D typescript wrangler
npx wrangler --version

C3 kann in neuen Projekten wrangler.jsonc erzeugen. Wrangler unterstützt JSON/JSONC und TOML; dieser Artikel nutzt TOML wegen der Lesbarkeit. Wenn dein Projekt wrangler.jsonc hat, übernimm dieselben Keys in JSONC.

name = "claude-worker-api"
main = "src/index.ts"
compatibility_date = "2026-06-03"

[vars]
PUBLIC_ENV = "production"

[observability]
enabled = true
head_sampling_rate = 1

[[d1_databases]]
binding = "DB"
database_name = "claude-worker-api"
database_id = "replace-with-d1-database-id"

[[kv_namespaces]]
binding = "SETTINGS"
id = "replace-with-kv-namespace-id"

[[r2_buckets]]
binding = "RECEIPTS"
bucket_name = "claude-worker-receipts"

[[ratelimits]]
name = "API_RATE_LIMITER"
namespace_id = "1001"

  [ratelimits.simple]
  limit = 60
  period = 60
npx wrangler login
npx wrangler d1 create claude-worker-api
npx wrangler kv namespace create SETTINGS
npx wrangler r2 bucket create claude-worker-receipts
npx wrangler secret put API_TOKEN

D1 Schema

CREATE TABLE IF NOT EXISTS orders (
  id TEXT PRIMARY KEY,
  email TEXT NOT NULL,
  amount INTEGER NOT NULL,
  status TEXT NOT NULL DEFAULT 'pending',
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_orders_email ON orders(email);
npx wrangler d1 execute claude-worker-api --local --file=./schema.sql
npx wrangler d1 execute claude-worker-api --remote --file=./schema.sql

Lauffähiger Worker

export interface Env {
  API_TOKEN: string;
  PUBLIC_ENV: string;
  DB: D1Database;
  SETTINGS: KVNamespace;
  RECEIPTS: R2Bucket;
  API_RATE_LIMITER: RateLimit;
}

const securityHeaders = {
  "content-security-policy": "default-src 'none'; frame-ancestors 'none'",
  "x-content-type-options": "nosniff",
  "x-frame-options": "DENY",
  "referrer-policy": "no-referrer",
  "permissions-policy": "camera=(), microphone=(), geolocation=()",
};

function json(data: unknown, init: ResponseInit = {}) {
  return new Response(JSON.stringify(data), {
    ...init,
    headers: {
      "content-type": "application/json; charset=utf-8",
      ...securityHeaders,
      ...init.headers,
    },
  });
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const url = new URL(request.url);
    const requestId = crypto.randomUUID();
    console.log({ event: "request_started", requestId, method: request.method, path: url.pathname });

    if (url.pathname === "/health") {
      const maintenance = await env.SETTINGS.get("maintenance");
      return json({ ok: true, env: env.PUBLIC_ENV, maintenance: maintenance === "true" });
    }

    if (request.headers.get("authorization") !== `Bearer ${env.API_TOKEN}`) {
      return json({ error: "unauthorized" }, { status: 401 });
    }

    const { success } = await env.API_RATE_LIMITER.limit({
      key: request.headers.get("authorization")?.slice(-16) ?? "anonymous",
    });
    if (!success) return json({ error: "rate_limited" }, { status: 429 });

    const match = url.pathname.match(/^\/orders\/([a-zA-Z0-9_-]+)$/);

    if (request.method === "GET" && match) {
      const cacheKey = new Request(url.toString(), { method: "GET" });
      const cached = await caches.default.match(cacheKey);
      if (cached) return cached;

      const order = await env.DB.prepare(
        "SELECT id, email, amount, status, created_at FROM orders WHERE id = ?"
      ).bind(match[1]).first();
      if (!order) return json({ error: "not_found" }, { status: 404 });

      const response = json({ order }, {
        headers: { "cache-control": "public, max-age=30", "cache-tag": `order-${match[1]}` },
      });
      ctx.waitUntil(caches.default.put(cacheKey, response.clone()));
      return response;
    }

    if (request.method === "POST" && url.pathname === "/orders") {
      const body = await request.json<{ email?: string; amount?: number }>();
      if (!body.email?.includes("@") || !Number.isInteger(body.amount) || body.amount <= 0) {
        return json({ error: "invalid_order" }, { status: 400 });
      }

      const id = crypto.randomUUID();
      await env.DB.prepare(
        "INSERT INTO orders (id, email, amount, status) VALUES (?, ?, ?, ?)"
      ).bind(id, body.email, body.amount, "pending").run();

      await env.RECEIPTS.put(`orders/${id}.json`, JSON.stringify({ id, email: body.email, amount: body.amount }), {
        httpMetadata: { contentType: "application/json" },
      });

      console.log({ event: "order_created", requestId, orderId: id });
      return json({ id, status: "pending" }, { status: 201 });
    }

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

Lokal testen und deployen

printf "API_TOKEN=dev-token\n" > .dev.vars
npx wrangler dev
curl http://localhost:8787/health

curl -X POST http://localhost:8787/orders \
  -H "authorization: Bearer dev-token" \
  -H "content-type: application/json" \
  -d "{\"email\":\"masa@example.com\",\"amount\":1200}"

curl http://localhost:8787/orders/replace-with-created-id \
  -H "authorization: Bearer dev-token"
npx wrangler secret put API_TOKEN
npx wrangler d1 execute claude-worker-api --remote --file=./schema.sql
npx wrangler deploy
npx wrangler tail

Praxisfälle

Erstens: Formular- oder Bestell-API. D1 speichert Status, R2 speichert Belege oder Anhänge, Workers Logs helfen bei Betrieb und Debugging.

Zweitens: Webhook Receiver. Signatur prüfen, Event ID in D1 speichern und Duplikate ignorieren.

Drittens: BFF, also Backend for Frontend. Der Worker versteckt API Keys, formt Antworten für die UI um und cached nur sichere Daten.

Viertens: Kontrollierte R2 Downloads. Die Datei liegt in R2, Autorisierung und Logs liegen im Worker.

Häufige Fehler

Schreibe Workers nicht wie dauerhaft laufende Node.js Server. Plane mit Web APIs, Request, Response, fetch, crypto und Bindings.

Vermische die Storage-Rollen nicht. KV ist für kleine Key-Value-Daten, D1 für relationale Daten, R2 für Objekte und Cache API für kurzlebige Antworten.

Cache keine privaten Antworten. Wenn Cookie, Token, E-Mail oder Nutzerkontext eine Rolle spielen, meide Shared Cache oder nutze sehr bewusste Keys und TTLs.

Rate-limite nicht nur nach IP. API Key, User ID oder Tenant ID sind meist stabiler.

Plattformwahl

Workers passt für latenzarme HTTP APIs nahe am Cloudflare Cache und den Bindings. Pages Functions passt, wenn eine Cloudflare Pages Site etwas dynamische Logik braucht. Cloud Run passt für Container, lange Jobs oder bestehende Frameworks. Lambda passt, wenn der Ablauf um AWS Dienste wie S3, DynamoDB, EventBridge oder SQS gebaut ist.

Review Prompt

Reviewe diese Cloudflare Workers Implementierung.

Prüfe:
- Workers Runtime Kompatibilität
- Gleichheit von Env Typen und Wrangler Bindings
- Secrets in Code, Logs oder Config
- D1 bind Nutzung und SQL Injection Risiko
- unsichere Cache API Nutzung
- Rate Limiting Key
- Security Headers auf jeder Antwort
- fehlende curl Prüfungen

Gib Findings nach Schweregrad, dann Fixes, dann Tests aus.

CTA und Prüfnachweis

Migriere zuerst nur einen Endpoint: /health, einen read-only GET oder einen Webhook. Gib Claude Code Dateien, Binding-Namen, Prüfkommandos und Verbote. Wiederverwendbare Templates findest du unter products; für Teamtraining und Review-Routinen nutze training.

Ergebnis des Praxistests: Den Ablauf aus Wrangler, D1, Worker und curl habe ich für diesen Artikel zusammengeführt; vor Produktion solltest du wrangler deploy, wrangler tail, Headers, Cache und 429-Verhalten in deinem Cloudflare Account erneut prüfen.

#Claude Code #Cloudflare Workers #Edge Computing #Serverless #API
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.