frontend / rendering modes / 07_edge_rendering.md

Edge Rendering and CDN-as-Runtime

7 min read source

Edge Rendering and CDN-as-Runtime

TL;DR

Edge rendering = your code runs at CDN edge nodes (geographically close to users), not in a central data center. Platforms: Cloudflare Workers (V8 isolates on ~300+ edge locations), Vercel Edge Functions, Netlify Edge Functions, AWS Lambda@Edge / CloudFront Functions, Deno Deploy, Fastly Compute@Edge. Trade-offs: faster TTFB + cold starts, but limited runtimes (V8 isolates, no full Node) and constrained DB access (HTTP-based clients only typically). The senior knowledge: when edge wins, when traditional regional serverless wins, and the “edge-friendly” architectural patterns.

Interview Q&A

Q: What’s an edge runtime?

A: A JS execution environment hosted at the CDN’s edge nodes. Instead of one server in us-east-1 handling all traffic, the user’s request hits the nearest of N edge locations (closest hop).

Two common runtimes:

  • V8 isolates (Cloudflare Workers, Vercel Edge, Deno Deploy) — lightweight V8 sandboxes, near-instant cold start (~5ms), but limited (Web Standard APIs, no Node native modules).
  • Lightweight Node (AWS Lambda@Edge) — full Node but heavier cold start.

The big win is TTFB: a Tokyo user hitting us-east-1 pays ~120ms RTT just for the network. Edge response from Tokyo: ~20ms RTT. 2-5× lower TTFB for global users.

Q: Edge vs traditional serverless?

A:

Edge runtime Regional serverless (Lambda, Node)
Where 100s of edge locations one region (us-east-1, eu-west-1)
Cold start ~5ms (V8 isolate) 100-500ms (cold), 0 (warm)
Runtime Web Standard APIs (fetch, Streams, crypto) full Node + ecosystem
Memory smaller (~128MB) larger (up to 10GB)
CPU time strict (~50ms on Vercel free, more on Cloudflare paid) up to 15 min Lambda
DB HTTP-based clients (Planetscale, Neon, Vercel Postgres HTTP) any Node driver
Use for read-heavy SSR, redirects, geo-personalization full SSR with heavy compute, native deps

Q: When does edge rendering win?

A:

  • Geographically distributed users — global SaaS, content sites.
  • Read-heavy routes — fetch a few values, render HTML. CPU cheap, network high.
  • Fast TTFB matters — marketing, e-commerce, content where bounce on slow load.
  • Personalization at the edge — A/B tests, feature flags, geo-redirects, header rewriting.
  • Always-on — no cold start hurts perf.

Q: When does edge not fit?

A:

  • Heavy compute — ML inference, image processing. Hits CPU limits.
  • Native dependencies — anything requiring Node native modules (sharp, native bindings).
  • Long-running requests — uploads, SSE, anything > 30-50s.
  • Complex DB access — most DB drivers are Node-only. Use HTTP-based DB or move to regional serverless.
  • Large dependencies — V8 isolates have bundle size limits (Cloudflare Workers: 10MB compressed total).

Q: Edge-friendly databases.

A: Edge runtimes can’t usually open TCP/TLS connections to Postgres/MySQL (no socket APIs in V8 isolates). Workarounds:

  • HTTP/REST-based DB clientsNeon (Postgres over HTTP), PlanetScale (MySQL over HTTP), Cloudflare D1 (SQLite on Cloudflare), Upstash Redis (HTTP-based).
  • Vercel Postgres — Postgres with HTTP query API specifically for edge.
  • Connection pooling proxiespgBouncer + HTTP wrapper (Supabase, Prisma Accelerate).

For an edge app, your DB choice and runtime are coupled. Pick a database with HTTP/edge support, or fall back to regional serverless.

Q: Cloudflare Workers specifics.

A: Cloudflare’s mature edge offering — distinct from Vercel/Netlify “edge functions” which are similar but smaller scale.

// worker.ts
export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname === "/api/hello") {
      return Response.json({ hello: "world" });
    }
    return new Response("Not found", { status: 404 });
  },
};

Features:

  • 300+ edge cities globally.
  • KV storage (eventually consistent key-value at the edge).
  • D1 (SQLite at the edge).
  • R2 (S3-compatible object storage, no egress fees).
  • Durable Objects (single-instance compute with persistent state — for collaborative apps).
  • Cron triggers (scheduled workers).

Cloudflare is the most feature-rich edge platform today. Vercel Edge is good if you’re already on Vercel; Cloudflare is the better standalone choice for serious edge architectures.

Q: Vercel Edge Functions and Middleware.

A: Two flavors:

  • Edge Middleware — runs on every request before reaching the route handler. For redirects, header rewriting, A/B testing, auth checks.
    // middleware.ts
    export const config = { matcher: ["/(.*)"] };
    export function middleware(req: NextRequest) {
      const country = req.geo?.country ?? "US";
      if (country === "DE" && !req.nextUrl.pathname.startsWith("/de")) {
        return NextResponse.redirect(new URL(`/de${req.nextUrl.pathname}`, req.url));
      }
    }
  • Edge Functions — full route handlers on the edge runtime (Next.js export const runtime = "edge").

Middleware is the killer feature — for things like geo-redirects, A/B variant assignment, header injection, the latency cost is tiny (a few ms), and it runs before origin compute.

Q: Caching at the edge.

A: Edge platforms layer cache on top of compute:

  • HTTP Cache-Control — edge nodes cache responses per the headers.
  • Cache API (Cloudflare Workers) — explicit caches.default.put(...) for custom cache control.
  • Stale-while-revalidate at the edge — serve stale, refresh in background.
  • Tag-based invalidation (Vercel) — revalidateTag purges from the edge.

For static + occasionally-personalized content: cache the static shell at the edge, inject personalization at the edge. Tens-of-ms TTFB, fresh data.

Q: ISR + edge — what’s the architecture?

A: Vercel + Next.js: ISR-rendered pages cached at the edge globally. First request triggers regen at the origin → cached at the edge → all subsequent requests served from the closest edge.

For a blog with revalidate = 60:

  • User in Tokyo: first request after revalidate triggers regen (slower); subsequent within 60s: ~10ms TTFB from Tokyo edge.

Combined with stale-while-revalidate: even the regen-triggering request serves stale immediately.

Q: Geo-personalization at the edge.

A: Edge runtimes expose request location (country, region, city) without lookup:

// Vercel Edge
export default function handler(req: NextRequest) {
  const country = req.geo?.country ?? "US";
  const city = req.geo?.city ?? "unknown";
  // route, personalize, A/B test based on geo
}

Use cases:

  • Redirect EU users to GDPR-compliant variant.
  • Show local currency / language.
  • A/B test buckets by region.
  • Block / allow by country.

Heavier server-side personalization (per-user, behavioral) usually goes back to regional servers; geo at the edge is cheap.

Q: A/B testing at the edge.

A: Assign variant in middleware, set a cookie, route to the right page version:

// middleware.ts
export function middleware(req: NextRequest) {
  let variant = req.cookies.get("ab-variant")?.value;
  if (!variant) {
    variant = Math.random() < 0.5 ? "A" : "B";
    const res = NextResponse.rewrite(new URL(`/variant-${variant}`, req.url));
    res.cookies.set("ab-variant", variant);
    return res;
  }
  return NextResponse.rewrite(new URL(`/variant-${variant}`, req.url));
}

The variant page can still be statically cached. Edge middleware bridges the “static + personalized” gap without forcing per-user SSR.

Q: Cost model.

A:

  • Cloudflare Workers — free tier (100K req/day), paid: $5/mo for 10M req + $0.30/M after. CPU billed in ms.
  • Vercel Edge Functions — included in Pro plan up to limits; extra usage billed.
  • AWS Lambda@Edge — $0.60/M invocations + $0.0000125/GB-second.

Edge is generally cheaper at scale than regional serverless because cold starts are cheap and CPU time is short (read-heavy SSR is fast). Heavy compute on edge gets expensive (CPU billing); push that to regional.

Gotchas / edge cases

  • Edge runtime API limitssetTimeout, setInterval, file system, native modules — often missing or limited. Read your platform’s “Edge runtime” docs carefully.
  • Bundle size limits — Cloudflare Workers cap at 10MB compressed; Vercel Edge similar. Heavy dependencies (Prisma client until v5) blow this.
  • Cold start is fast, not zero — V8 isolates spin up in ~5ms. For sub-millisecond, cache the response at the CDN layer.
  • DB connection limits — edge requests come from N edge locations, each opening DB connections. Pool via HTTP-based DB or connection-pooling proxy. Traditional DB pooling assumes one region.
  • Logging + observability — edge logs scatter across regions. Use platform-native logging (Cloudflare Analytics, Vercel Observability) or ship to a centralized service.
  • CORS at the edge — make sure edge responses set CORS headers correctly; CDN caching can mask CORS issues.

What a senior is expected to say

  • “Edge rendering runs your code at CDN locations close to users — lower TTFB (2-5x for global users), faster cold starts (~5ms vs 100-500ms regional).”
  • “Trade-off: V8 isolate runtimes have limited APIs and bundle sizes, can’t open TCP to traditional DBs. Use HTTP-based clients (Neon, Planetscale, Vercel Postgres HTTP).”
  • “Use edge for read-heavy SSR, redirects, geo-personalization, A/B test assignment, header rewriting. Push heavy compute or native deps to regional serverless.”
  • “Cloudflare Workers is the most feature-rich edge platform (KV, D1, R2, Durable Objects, Cron). Vercel Edge is the natural choice in the Next.js ecosystem.”
  • “ISR + edge gives near-instant TTFB globally — pages cached at every edge location, regen triggered on stale request.”
  • “Edge middleware for things that need to run before origin compute — geo redirects, A/B buckets, auth checks. Cheap latency, big architectural value.”

Cross-references

Further reading