Use Cases (Diperbarui: 2/6/2026)

Vercel Edge Functions dengan Claude Code: panduan praktis

Gunakan Vercel Edge Runtime dengan Claude Code: Middleware, signed webhook, A/B test, cache, dan jebakan produksi.

Vercel Edge Functions dengan Claude Code: panduan praktis

Jangan memilih Edge hanya karena terdengar cepat

Vercel Edge Functions menjalankan JavaScript di Edge Runtime. Ini bukan proses Node.js biasa, melainkan runtime kecil berbasis Web API seperti fetch, Request, Response, URL, TextEncoder, dan Web Crypto. Sederhananya, Edge adalah gerbang ringan sebelum request masuk ke halaman atau API yang lebih berat. Ia bisa membaca URL, header, cookie, dan body kecil, lalu mengambil keputusan cepat.

Claude Code berguna karena perubahan Edge yang nyata jarang hanya menyentuh satu file. Redirect berdasarkan negara menyentuh middleware.ts, header Vercel, dan perbedaan local dengan preview. A/B test menyentuh cookie, request header, analytics, dan rollback. Webhook bertanda tangan menyentuh raw body, HMAC, environment variable, batas ukuran body, dan forwarding ke layanan internal. Jadi, minta Claude Code meninjau batas runtime, bukan hanya membuat fungsi.

Per Juni 2026, dokumentasi resmi Vercel Edge Runtime menjelaskan API yang tersedia, limit, region, dan kasus ketika Node.js lebih tepat untuk performance atau reliability. Dokumentasi Next.js untuk Middleware dan Route Handlers juga memakai model Web Request dan Response. Aturan praktisnya: keputusan kecil di pintu masuk boleh di Edge, pekerjaan yang tahan lama tetap di backend.

Untuk topik lanjutan, baca Claude Code webhook implementation dan Claude Code performance optimization. Keduanya membantu memisahkan signature, retry, idempotency, cache, dan pengukuran.

Lima use case praktis

Edge paling cocok ketika jawaban bisa ditentukan dari metadata request atau payload kecil yang ditandatangani. Edge kurang cocok untuk dependency besar, transaksi database panjang, koneksi private network, upload besar, atau stream LLM yang lama.

Use caseMengapa cocok di EdgeSimpan di Node.js atau backend
Redirect negarax-vercel-ip-country bisa dibaca sebelum renderPreferensi pengguna, pricing, account policy
A/B testCookie membuat bucket stabil sebelum halaman direnderAgregasi, analisis statistik, keputusan rollout
Auth ringan atau signatureRequest preview atau webhook invalid ditolak lebih awalSession, role, audit log
Cache preprocessingURL dan query dinormalisasi agar cache key stabilRevalidation, inventory, komputasi mahal
Menerima webhookRaw body kecil diverifikasi lalu diteruskanFinalisasi pembayaran, email, retry, CRM

Tabel ini juga bisa dipakai sebagai prompt Claude Code. Jelaskan mana yang boleh berada di Edge dan mana yang harus tetap di backend. Dengan begitu, kode yang dihasilkan lebih kecil kemungkinan memakai API Node-only, koneksi database langsung, atau log berisi secret.

flowchart LR
  A["User request"] --> B["Next.js Middleware"]
  B --> C{"Small decision"}
  C --> D["Country redirect"]
  C --> E["A/B bucket"]
  C --> F["Light auth"]
  B --> G["Edge Route Handler"]
  G --> H["HMAC signature check"]
  H --> I["Internal API or queue"]

Diagram ini menempatkan Edge sebagai lapisan masuk, bukan backend penuh. Middleware mengklasifikasi request dan menambahkan metadata. Route Handler memverifikasi webhook kecil. Efek samping yang butuh retry dan audit pindah ke API internal, queue, atau worker.

Middleware Next.js yang bisa disalin

middleware.ts berikut berisi redirect negara, bucket A/B, gate ringan untuk preview, dan security headers. Contoh ini memakai header Vercel, bukan request.geo, agar lebih stabil terhadap perbedaan versi Next.js. Di local, x-vercel-ip-country biasanya tidak ada, jadi uji bagian itu di Vercel Preview Deployment.

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

const PUBLIC_FILE = /\.(?:png|jpg|jpeg|gif|svg|webp|ico|css|js|map|txt)$/i;
const SECRET_HEADER = "x-edge-shared-secret";

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

function chooseBucket(request: NextRequest): "a" | "b" {
  const current = request.cookies.get("ab_bucket")?.value;
  if (current === "a" || current === "b") return current;

  const random = new Uint8Array(1);
  crypto.getRandomValues(random);
  return random[0] < 128 ? "a" : "b";
}

function localeFromCountry(country: string | null): string | null {
  switch (country?.toUpperCase()) {
    case "JP":
      return "ja";
    case "KR":
      return "ko";
    case "CN":
    case "TW":
    case "HK":
      return "zh";
    case "BR":
      return "pt";
    case "ES":
    case "MX":
      return "es";
    default:
      return null;
  }
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  if (PUBLIC_FILE.test(pathname)) {
    return NextResponse.next();
  }

  if (pathname === "/") {
    const country = request.headers.get("x-vercel-ip-country");
    const locale = localeFromCountry(country);
    if (locale) {
      return NextResponse.redirect(new URL(`/${locale}/`, request.url), 307);
    }
  }

  if (pathname.startsWith("/beta")) {
    const bucket = chooseBucket(request);
    const requestHeaders = new Headers(request.headers);
    requestHeaders.set("x-ab-bucket", bucket);

    const response = NextResponse.next({
      request: { headers: requestHeaders },
    });

    if (!request.cookies.has("ab_bucket")) {
      response.cookies.set("ab_bucket", bucket, {
        maxAge: 60 * 60 * 24 * 30,
        path: "/",
        sameSite: "lax",
        secure: request.nextUrl.protocol === "https:",
      });
    }

    return response;
  }

  if (pathname.startsWith("/preview")) {
    const expected = process.env.EDGE_SHARED_SECRET;
    const actual = request.headers.get(SECRET_HEADER);
    if (!expected || actual !== expected) {
      return NextResponse.redirect(new URL("/login", request.url), 307);
    }
  }

  const response = NextResponse.next();
  response.headers.set("x-content-type-options", "nosniff");
  response.headers.set("referrer-policy", "strict-origin-when-cross-origin");
  return response;
}

Contoh ini sengaja kecil. A/B test hanya memilih bucket, bukan menentukan pemenang. Preview gate bukan sistem auth penuh. Redirect negara hanya berjalan di / agar tidak membuat loop.

Edge Route Handler untuk webhook bertanda tangan

Contoh app/api/webhooks/provider/route.ts ini memverifikasi signature HMAC. HMAC berarti pengirim dan penerima berbagi secret, lalu menghitung signature dari body asli. Di Edge Runtime, gunakan Web Crypto dan TextEncoder, bukan crypto.createHmac atau Buffer.

// app/api/webhooks/provider/route.ts
export const runtime = "edge";
export const preferredRegion = ["iad1", "hnd1"];

const MAX_BODY_BYTES = 256_000;

function hexToBytes(hex: string): Uint8Array {
  const clean = hex.replace(/^sha256=/, "").trim();
  if (!/^[0-9a-f]+$/i.test(clean) || clean.length % 2 !== 0) {
    return new Uint8Array();
  }

  const bytes = new Uint8Array(clean.length / 2);
  for (let index = 0; index < clean.length; index += 2) {
    bytes[index / 2] = Number.parseInt(clean.slice(index, index + 2), 16);
  }
  return bytes;
}

async function hmacSha256(secret: string, payload: string): Promise<Uint8Array> {
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"],
  );
  const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
  return new Uint8Array(signature);
}

function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
  if (a.length !== b.length) return false;

  let diff = 0;
  for (let index = 0; index < a.length; index += 1) {
    diff |= a[index] ^ b[index];
  }
  return diff === 0;
}

export async function POST(request: Request) {
  const secret = process.env.WEBHOOK_SECRET;
  const internalOrigin = process.env.INTERNAL_API_ORIGIN;
  const internalToken = process.env.INTERNAL_API_TOKEN;

  if (!secret || !internalOrigin || !internalToken) {
    return Response.json({ error: "server is not configured" }, { status: 500 });
  }

  const contentLength = Number(request.headers.get("content-length") ?? "0");
  if (contentLength > MAX_BODY_BYTES) {
    return Response.json({ error: "payload too large" }, { status: 413 });
  }

  const rawBody = await request.text();
  const rawBodyBytes = new TextEncoder().encode(rawBody);
  if (rawBodyBytes.byteLength > MAX_BODY_BYTES) {
    return Response.json({ error: "payload too large" }, { status: 413 });
  }

  const provided = hexToBytes(request.headers.get("x-signature-sha256") ?? "");
  const expected = await hmacSha256(secret, rawBody);
  if (!constantTimeEqual(provided, expected)) {
    return Response.json({ error: "invalid signature" }, { status: 401 });
  }

  const event = JSON.parse(rawBody) as { id?: string; type?: string };
  if (!event.id || !event.type) {
    return Response.json({ error: "invalid event" }, { status: 400 });
  }

  await fetch(`${internalOrigin}/api/webhook-events`, {
    method: "POST",
    headers: {
      authorization: `Bearer ${internalToken}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      id: event.id,
      type: event.type,
      receivedAt: new Date().toISOString(),
    }),
  });

  return Response.json({ ok: true });
}

Urutannya penting: batasi ukuran, baca raw body, verifikasi signature, parse JSON, lalu teruskan event. Payment final, email, dan retry lebih aman dikerjakan layanan internal yang mendukung idempotency.

Prompt review Claude Code dan test minimal

Gunakan prompt ini agar Claude Code memeriksa batas Edge Runtime:

Review this Next.js Edge implementation.

Scope:
- middleware.ts
- app/api/webhooks/provider/route.ts
- related tests and environment variable names

Check:
- no Node-only APIs such as fs, net, tls, Buffer, or node:crypto in Edge files
- no direct database connection from Edge Runtime
- country redirect does not loop
- A/B bucket is stable by cookie and not written on every request
- webhook verifies the raw body before JSON parsing
- secrets, signatures, cookies, and authorization headers are not logged
- body size and production-only Vercel headers are documented

Return blockers first, then suggested tests.

Untuk test local, Node.js boleh dipakai membuat signature karena helper ini tidak berjalan di Edge.

npm run lint
npm run build
vercel dev

BODY='{"id":"evt_123","type":"checkout.completed"}'
SIG=$(node -e "const crypto=require('crypto'); const body=process.argv[1]; console.log('sha256='+crypto.createHmac('sha256', process.env.WEBHOOK_SECRET).update(body).digest('hex'))" "$BODY")

curl -i http://localhost:3000/api/webhooks/provider \
  -X POST \
  -H "content-type: application/json" \
  -H "x-signature-sha256: $SIG" \
  --data "$BODY"

curl -I http://localhost:3000/beta
curl -I http://localhost:3000/preview

Di Preview Deployment, periksa header negara, cookie HTTPS, loop redirect, log, dan asumsi region. vercel dev penting, tetapi tidak sepenuhnya sama dengan produksi.

Jebakan umum

Jebakan pertama adalah memakai API Node.js tanpa sadar. fs, Buffer, crypto.createHmac, native module, dan database client berbasis TCP tidak cocok untuk file Edge. Periksa juga import tidak langsung.

Jebakan kedua adalah koneksi database langsung dari Edge. Jika database hanya berada di satu region, request tetap harus pergi ke region itu dan bisa menambah tekanan koneksi. Gunakan HTTP API, queue, atau Node.js Function dekat database.

Jebakan ketiga adalah salah memahami cold start dan region. Edge dapat mengurangi latency di pintu masuk, tetapi tidak membuat data jauh menjadi lokal. preferredRegion perlu dibuktikan dengan log dan metrik.

Jebakan keempat adalah secret bocor di log. Body webhook, signature, cookie, Authorization header, dan preview secret tidak boleh dicetak apa adanya.

Jebakan kelima adalah body size dan streaming. Edge cocok untuk request kecil, bukan upload besar, CSV, pemrosesan gambar, atau stream LLM panjang.

Jebakan keenam adalah perbedaan local dan produksi. vercel dev tidak meniru semua header Vercel, region nyata, preview logs, dan perilaku secure cookie.

CTA ClaudeCodeLab

Untuk proyek pribadi, contoh ini cukup untuk prototipe. Untuk tim, yang sulit adalah aturan: file mana boleh memakai Edge Runtime, API mana dilarang, bagaimana environment variable dinamai, dan siapa yang memverifikasi Preview Deployment.

ClaudeCodeLab membantu mengubahnya menjadi aturan Claude Code, CLAUDE.md, prompt review, receipt verifikasi webhook, dan check Vercel. Jika ingin menerapkannya ke repository nyata, mulai dari Claude Code training and consultation. Tujuannya bukan menambah birokrasi, tetapi mencegah perubahan middleware kecil menjadi masalah seluruh situs.

Hasil setelah dicoba

Saat pola ini dicoba, manfaat terbesar adalah kejelasan. Middleware hanya mengurus redirect, A/B bucket, header, dan blocking ringan. Edge Route Handler memverifikasi webhook kecil lalu meneruskan event. Prompt review membantu menemukan Buffer, JSON parse sebelum raw body diverifikasi, header Vercel yang tidak ada di local, dan log yang terlalu detail. Edge Functions bukan sihir performa, tetapi sangat berguna ketika batas request kecil dan mudah dites.

#Claude Code #Vercel #Edge Functions #edge computing #serverless
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.