The Edge Runtime gets pitched as a free performance win — just add export const runtime = 'edge' and your route gets faster. That's only true for a narrow set of routes. The Edge Runtime is a genuinely restricted environment, not a faster flavor of Node, and picking it for the wrong route trades a working feature for a marginal latency gain, or breaks outright when a dependency assumes Node APIs that simply aren't there.
What the Edge Runtime actually is
Next.js's Edge Runtime is built on the same constrained execution model as Cloudflare Workers and Vercel's edge functions: a V8 isolate, not a full Node.js process. You get Web-standard APIs — fetch, Request/Response, URL, crypto.subtle, streams — and nothing that depends on Node's runtime internals. No fs, no native addons, no arbitrary net/child_process access, and no npm package that reaches into Node internals under the hood, even transitively. It starts faster than a Node.js process because there's no full runtime to boot — this is the actual reason it exists, not because the code runs faster once started.
// middleware.ts — always runs on the Edge Runtime, no opt-in needed
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('session')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = { matcher: ['/dashboard/:path*'] };
What breaks when you set runtime = 'edge'
The failure mode is usually a build-time or runtime error from a dependency, not your own code. ORMs and database drivers that use raw TCP sockets (most traditional Postgres/MySQL drivers) don't work on the Edge Runtime — you need an HTTP-based driver built for it (Neon's serverless driver, PlanetScale's HTTP driver, Prisma's Accelerate/Data Proxy) instead of the standard driver. Libraries that read from the filesystem, spawn subprocesses, or rely on Node's Buffer in ways the edge polyfill doesn't cover will also fail. Middleware runs on the Edge Runtime unconditionally in Next.js — you can't opt it into Node — so any package you pull into middleware has to be edge-compatible by definition.
Unlike route handlers and pages, where you choose the runtime, Next.js middleware always executes on the Edge Runtime. If you need something Node-only (a database driver, a heavy crypto library, `fs` access) in request-gating logic, do the minimal check in middleware and defer the Node-dependent work to a route handler running with export const runtime = 'nodejs'.
When edge is worth choosing on purpose
Edge makes sense for routes that are latency-sensitive, stateless, and don't need Node-specific dependencies: auth checks, A/B test bucketing, geolocation-based redirects, lightweight API proxying, and simple response rewriting. It's a poor fit for anything doing heavy computation, using a traditional database driver, generating PDFs or images with native libraries, or anything that benefits from Node's broader ecosystem more than it benefits from a faster cold start. If your app runs on a single-region Node server rather than a multi-region edge network, the cold-start advantage of Edge over Node mostly disappears — you're paying the compatibility cost without the latency win.
// app/api/geo-redirect/route.ts — good edge candidate: no DB, no heavy compute
export const runtime = 'edge';
export function GET(request: Request) {
const country = request.headers.get('x-vercel-ip-country') ?? 'US';
const target = country === 'KE' ? '/ke' : '/global';
return Response.redirect(new URL(target, request.url));
}
// app/api/reports/route.ts — needs a real DB driver and PDF generation: Node
export const runtime = 'nodejs';
export async function GET() {
const rows = await db.query('SELECT * FROM invoices WHERE ...');
const pdf = await generatePdf(rows);
return new Response(pdf, { headers: { 'Content-Type': 'application/pdf' } });
}
Cold starts are the real trade-off, not raw speed
Edge Runtime cold starts are consistently faster than Node.js cold starts because there's no full Node process to spin up — this matters most for infrequently-hit routes on serverless infrastructure where every request risks a cold start. On a warm, always-running Node.js server, the cold-start advantage is irrelevant, and Node's per-request performance for compute-heavy work is often better once warm. Choosing Edge for its cold-start behavior only pays off if your deployment target actually experiences frequent cold starts in the first place.
Wrapping up
The Edge Runtime is a real, useful tool for a specific job — fast-starting, stateless, Web-API-only logic close to the request — not a universal performance upgrade. Check what your route actually depends on before flipping the runtime flag: a traditional database driver or a Node-only package will fail loudly, and a compute-heavy route won't get faster just because it's labeled edge.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.