Skip to main content
Back to Articles
Next.jsDecember 15, 20257 min read

Next.js Edge Functions for Global Performance

Leverage Next.js Edge Runtime and middleware for sub-50ms global response times with geo-routing, A/B testing, and personalized content delivery.

Why Edge Computing Matters

Traditional server-side rendering runs in a single region. A user in Sydney requesting a page from a server in Virginia adds 200-300ms of network latency before any processing begins. Edge functions execute in data centers closest to the user, eliminating this round-trip penalty.

Next.js Edge Runtime runs a subset of Node.js APIs on V8 isolates at the edge, enabling sub-50ms response times globally. This guide covers practical patterns for using edge functions in production, from the perspective of teams focused on server optimization.

Edge Runtime vs Node.js Runtime

Understanding the tradeoffs is critical before choosing where to run your code:

Edge Runtime: Cold starts under 5ms, runs in 30+ global locations, limited API surface (no filesystem, no native Node modules), 128MB memory limit, 25ms CPU time limit per request.

Node.js Runtime: Full Node.js API access, runs in a single region, cold starts of 250ms+, unlimited CPU time, up to 1GB memory.

Use Edge for lightweight, latency-sensitive operations. Use Node.js for heavy computation, database queries, and operations requiring full Node.js APIs.

Middleware for Global Routing

Next.js middleware runs on every request before routing. On the Edge Runtime, it executes at the nearest edge location:

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

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

  // Set geo header for downstream components
  response.headers.set("x-user-country", country);

  // Redirect to country-specific store
  if (request.nextUrl.pathname === "/shop") {
    const storeMap: Record<string, string> = {
      DE: "/shop/eu",
      FR: "/shop/eu",
      GB: "/shop/uk",
      JP: "/shop/asia",
    };
    const targetPath = storeMap[country];
    if (targetPath) {
      return NextResponse.redirect(new URL(targetPath, request.url));
    }
  }

  return response;
}

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

Edge API Routes

Create API routes that run at the edge for latency-critical endpoints:

// app/api/feature-flags/route.ts
import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

const flags: Record<string, { enabled: boolean; rollout: number }> = {
  new_checkout: { enabled: true, rollout: 0.25 },
  dark_mode: { enabled: true, rollout: 1.0 },
  ai_search: { enabled: false, rollout: 0 },
};

export async function GET(request: NextRequest) {
  const userId = request.headers.get("x-user-id") || "anonymous";

  const userFlags = Object.fromEntries(
    Object.entries(flags).map(([key, config]) => {
      if (!config.enabled) return [key, false];
      const hash = simpleHash(userId + key);
      return [key, hash < config.rollout];
    })
  );

  return NextResponse.json(userFlags, {
    headers: {
      "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
    },
  });
}

function simpleHash(str: string): number {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    hash = (hash << 5) - hash + str.charCodeAt(i);
    hash |= 0;
  }
  return Math.abs(hash) / 2147483647;
}

A/B Testing at the Edge

Run A/B tests without client-side flicker by assigning variants at the edge:

// middleware.ts (A/B testing section)
function handleABTest(request: NextRequest): NextResponse {
  const experiment = "pricing-page-v2";
  const cookieName = `ab-${experiment}`;

  let variant = request.cookies.get(cookieName)?.value;

  if (!variant) {
    variant = Math.random() < 0.5 ? "control" : "treatment";
  }

  const url = request.nextUrl.clone();
  if (url.pathname === "/pricing" && variant === "treatment") {
    url.pathname = "/pricing-v2";
  }

  const response = NextResponse.rewrite(url);
  response.cookies.set(cookieName, variant, {
    maxAge: 60 * 60 * 24 * 30,
    httpOnly: true,
    sameSite: "lax",
  });

  return response;
}

This approach rewrites the URL internally — the user sees /pricing in their browser while the server renders the variant page. No layout shift, no flicker, no client-side JavaScript required.

Edge-Optimized Authentication

Validate JWT tokens at the edge to protect routes without a round-trip to your auth server:

// lib/edge-auth.ts
export async function verifyToken(token: string): Promise<boolean> {
  try {
    const [headerB64, payloadB64, signatureB64] = token.split(".");
    const data = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
    const signature = base64UrlDecode(signatureB64);

    const key = await crypto.subtle.importKey(
      "jwk",
      PUBLIC_JWK,
      { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
      false,
      ["verify"]
    );

    const valid = await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, signature, data);
    if (!valid) return false;

    const payload = JSON.parse(atob(payloadB64));
    return payload.exp > Date.now() / 1000;
  } catch {
    return false;
  }
}

Performance Monitoring

Track edge function performance with custom headers:

export function middleware(request: NextRequest) {
  const start = Date.now();
  const response = NextResponse.next();
  response.headers.set("x-edge-latency", `${Date.now() - start}ms`);
  response.headers.set("x-edge-region", process.env.VERCEL_REGION || "unknown");
  return response;
}

Best Practices

  • Keep edge functions under 1MB after bundling — large bundles increase cold start times
  • Use Cache-Control headers aggressively for edge API responses
  • Avoid importing heavy libraries — prefer Web API equivalents (crypto.subtle over jsonwebtoken)
  • Test with realistic latency using tools like tc or Chrome DevTools network throttling
  • Monitor edge function execution times and error rates in your observability platform
  • Combine edge functions with a robust infrastructure setup for a complete performance strategy

Edge computing shifts latency-sensitive logic closer to users, delivering measurable improvements in Time to First Byte and overall user experience.

Need help with this?

Our team handles this kind of work daily. Let us take care of your infrastructure.