Skip to main content
Technology & EngineeringEdge Computing220 lines

Vercel Edge

Vercel Edge Functions for low-latency compute within the Vercel deployment platform

Quick Summary18 lines
You are an expert in Vercel Edge Functions for building edge-first applications that run on Vercel's global edge network.

## Key Points

- Execution time: 30s max (streaming responses can run longer)
- Code size: 1 MB after gzip for Edge Functions, 4 MB for Middleware
- No Node.js filesystem, child_process, or native addons
- Limited Node.js API compatibility via the Edge Runtime polyfills
- **Keep Middleware lean** — it runs on every matched request. Avoid expensive computation or external API calls in Middleware.
- **Leverage Edge Config for feature flags and configuration** — reads are sub-millisecond and globally consistent within seconds of an update.
- **Use `matcher` in Middleware config** — avoid running Middleware on static asset paths to reduce unnecessary invocations.
- **Stream long responses** — Edge Functions support streaming, which avoids buffering large payloads and improves time-to-first-byte.
- **Test locally with `next dev`** — the local dev server simulates the Edge Runtime; also use `vercel dev` for closer fidelity.
- **Importing Node.js-only packages** — Libraries that use `fs`, `net`, `child_process`, or native modules will fail at the edge. Check compatibility before importing.
- **Assuming Middleware is invoked once per page load** — Middleware runs for every request including client-side navigations, images, and scripts unless the matcher is configured.
- **Writing to Edge Config from Edge Functions** — Edge Config is read-optimized. Writes must go through the Vercel REST API or dashboard, not from edge code.
skilldb get edge-computing-skills/Vercel EdgeFull skill: 220 lines
Paste into your CLAUDE.md or agent config

Vercel Edge Functions — Edge Computing

You are an expert in Vercel Edge Functions for building edge-first applications that run on Vercel's global edge network.

Overview

Vercel Edge Functions run on the Edge Runtime, a lightweight subset of the Web API that executes at Vercel's edge locations worldwide. They integrate tightly with Next.js (as Edge API Routes and Middleware) but also work in standalone mode. Edge Functions use V8 isolates, boot in under 1ms, and have no cold start penalty.

Key constraints:

  • Execution time: 30s max (streaming responses can run longer)
  • Code size: 1 MB after gzip for Edge Functions, 4 MB for Middleware
  • No Node.js filesystem, child_process, or native addons
  • Limited Node.js API compatibility via the Edge Runtime polyfills

Core Concepts

Edge Runtime Configuration

Mark any Next.js API route or page to run at the edge:

// app/api/hello/route.ts (App Router)
export const runtime = "edge";

export async function GET(request: Request) {
  return Response.json({ message: "Hello from the edge", timestamp: Date.now() });
}

Middleware

Middleware runs before every request at the edge, ideal for redirects, rewrites, auth, and A/B testing:

// middleware.ts (project root)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const country = request.geo?.country ?? "US";

  if (country === "DE") {
    return NextResponse.redirect(new URL("/de", request.url));
  }

  const response = NextResponse.next();
  response.headers.set("x-edge-region", request.geo?.region ?? "unknown");
  return response;
}

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

Edge Config

Vercel Edge Config is a global, ultra-low-latency key-value store designed for reading configuration at the edge:

import { get } from "@vercel/edge-config";

export const runtime = "edge";

export async function GET() {
  const featureFlags = await get<Record<string, boolean>>("featureFlags");
  return Response.json({ flags: featureFlags });
}

Implementation Patterns

A/B Testing at the Edge

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

const EXPERIMENT_COOKIE = "ab-experiment";

export function middleware(request: NextRequest) {
  const bucket = request.cookies.get(EXPERIMENT_COOKIE)?.value;

  if (bucket) {
    const url = request.nextUrl.clone();
    url.pathname = `/${bucket}${url.pathname}`;
    return NextResponse.rewrite(url);
  }

  const newBucket = Math.random() < 0.5 ? "control" : "variant";
  const url = request.nextUrl.clone();
  url.pathname = `/${newBucket}${url.pathname}`;

  const response = NextResponse.rewrite(url);
  response.cookies.set(EXPERIMENT_COOKIE, newBucket, {
    maxAge: 60 * 60 * 24 * 30,
    httpOnly: true,
  });
  return response;
}

Streaming Responses

// app/api/stream/route.ts
export const runtime = "edge";

export async function GET() {
  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      for (let i = 0; i < 10; i++) {
        controller.enqueue(encoder.encode(`data: Event ${i}\n\n`));
        await new Promise((resolve) => setTimeout(resolve, 500));
      }
      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    },
  });
}

Geolocation-Based Content

// app/api/pricing/route.ts
export const runtime = "edge";

const PRICING: Record<string, { currency: string; multiplier: number }> = {
  US: { currency: "USD", multiplier: 1.0 },
  GB: { currency: "GBP", multiplier: 0.79 },
  EU: { currency: "EUR", multiplier: 0.92 },
  JP: { currency: "JPY", multiplier: 149.5 },
};

export async function GET(request: Request) {
  const country = (request as any).geo?.country ?? "US";
  const region = PRICING[country] ?? PRICING["US"];
  const basePrice = 29.99;

  return Response.json({
    price: (basePrice * region.multiplier).toFixed(2),
    currency: region.currency,
    country,
  });
}

Rate Limiting with Edge Config

// middleware.ts
import { get } from "@vercel/edge-config";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  const blockedIps = await get<string[]>("blockedIps");
  const ip = request.ip ?? request.headers.get("x-forwarded-for") ?? "unknown";

  if (blockedIps?.includes(ip)) {
    return new NextResponse("Forbidden", { status: 403 });
  }

  return NextResponse.next();
}

Best Practices

  • Use runtime = "edge" selectively — only apply it to routes that benefit from edge proximity; data-heavy routes that call a single-region database are often faster on Node.js serverless functions near the DB.
  • Keep Middleware lean — it runs on every matched request. Avoid expensive computation or external API calls in Middleware.
  • Leverage Edge Config for feature flags and configuration — reads are sub-millisecond and globally consistent within seconds of an update.
  • Use matcher in Middleware config — avoid running Middleware on static asset paths to reduce unnecessary invocations.
  • Stream long responses — Edge Functions support streaming, which avoids buffering large payloads and improves time-to-first-byte.
  • Test locally with next dev — the local dev server simulates the Edge Runtime; also use vercel dev for closer fidelity.

Common Pitfalls

  • Importing Node.js-only packages — Libraries that use fs, net, child_process, or native modules will fail at the edge. Check compatibility before importing.
  • Assuming Middleware is invoked once per page load — Middleware runs for every request including client-side navigations, images, and scripts unless the matcher is configured.
  • Writing to Edge Config from Edge Functions — Edge Config is read-optimized. Writes must go through the Vercel REST API or dashboard, not from edge code.
  • Expecting consistent request.ip — The IP may be undefined in local development or behind certain proxies. Always provide a fallback.
  • Exceeding the 1 MB bundle limit — Large dependencies push bundles over the limit. Use dynamic imports or move heavy logic to serverless functions.
  • Blocking responses on slow origin fetches — If you fetch from a distant origin, the edge advantage is lost. Pair edge functions with edge-local data stores (KV, D1, Edge Config) for best latency.

Core Philosophy

Vercel Edge Functions are most powerful when used selectively. Not every route benefits from running at the edge — a page that fetches all its data from a single-region database is often faster as a Node.js serverless function colocated with that database. Apply runtime = "edge" to routes where low-latency, globally distributed execution provides a genuine advantage: authentication checks, A/B testing, geo-personalization, and serving cached or computed content that does not depend on a distant origin.

Middleware is the edge's greatest leverage point. It runs before every matched request with sub-millisecond overhead, making it the ideal place for redirects, rewrites, header injection, and authentication gating. But that power demands discipline — Middleware should be lean, fast, and free of external API calls. A slow Middleware function adds latency to every single page load.

Edge Config is the configuration layer purpose-built for edge reading. Its sub-millisecond reads make it ideal for feature flags, blocked IP lists, and application configuration that changes occasionally but is read on every request. Use it as the edge-native alternative to fetching configuration from a database or API on each request.

Anti-Patterns

  • Applying runtime = "edge" to every route — routes that query a single-region database lose the edge advantage and add latency from cross-region database calls; only use edge for routes that benefit from proximity to users.

  • Performing expensive operations in Middleware — Middleware runs on every matched request; adding API calls, database queries, or heavy computation to it multiplies latency across the entire application.

  • Importing Node.js-only packages in edge functions — libraries using fs, net, child_process, or native modules fail at the edge; verify compatibility before importing.

  • Not using the matcher config in Middleware — without a matcher, Middleware runs on static assets, images, and framework internals; always scope Middleware to the routes that need it.

  • Writing to Edge Config from edge functions — Edge Config is read-optimized; writes must go through the Vercel REST API or dashboard; attempting to write from edge code will fail.

Install this skill directly: skilldb add edge-computing-skills

Get CLI access →