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 clients —
Neon(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 proxies —
pgBouncer+ 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) —
revalidateTagpurges 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 limits —
setTimeout,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
- Next.js edge runtime: 05_nextjs_rendering_control.md
- HTTP caching headers: ../18_browser_internals/08_caching_headers.md
- Frontend system design (where edge fits): ../14_frontend_system_design/
- Backend CDN: ../../backend/28_networking/13_cdn.md
Further reading
- Cloudflare Workers docs: https://developers.cloudflare.com/workers/
- Vercel Edge Functions: https://vercel.com/docs/functions/edge-functions
- Neon (Postgres for edge): https://neon.tech/docs/serverless/serverless-driver
- “Edge rendering” — patterns.dev: https://www.patterns.dev/