Vercel Edge Functions run on a V8 isolate close to the user, with cold starts measured in milliseconds. That sounds like a free win — until you remember that a pre-rendered static page is even faster, and Node serverless gives you the full npm ecosystem. This article walks through where Edge is the right tool for a content site, and where it costs you more than it gives.
Background
Vercel offers three compute targets: static (pre-rendered at build), Node serverless functions (full Node runtime, ~300ms cold start), and Edge Functions (V8 isolate, ~50ms cold start, runs in 18+ regions). Edge has hard limits: no native Node modules, 4 MB code size, 1.5 MB request body, limited APIs. Content sites mostly need static; the rest of this article covers the exceptions.
How to tell
- You hit a function on every page load and the cold start is visible in your real-user metrics.
- You need geolocation, A/B testing, or auth checks before serving the page — not after.
- Your function is small (under 1 MB), pure JS, and does not need filesystem or native modules.
- You see Time-to-First-Byte spikes from users far from your function region.
Quick verdict
If the work is “rewrite, redirect, geo-route, set a cookie, read a header” — Edge wins. If it is “render the page, generate an OG image, hit a database with a fat ORM” — pick Node serverless or just pre-render. Static beats both for pure content.
When Edge Functions actually win
Three patterns where Edge meaningfully outperforms Node serverless for a content site:
- Geo-aware redirects in middleware. Routing
/to/en/or/zh/based onAccept-Languageor country code — Edge runs before the cache and adds maybe 20ms:
// middleware.ts
import { NextResponse, NextRequest } from 'next/server';
export const config = { matcher: ['/'] };
export function middleware(req: NextRequest) {
const country = req.geo?.country ?? 'US';
const lang = country === 'CN' || country === 'TW' ? 'zh' : 'en';
return NextResponse.redirect(new URL(`/${lang}/`, req.url));
}
- A/B testing with cookie persistence. Bucket users on first visit, set a cookie, keep them stable. The bucket decision needs to be before the cache, so middleware is the right place:
// middleware.ts — bucket and rewrite to a variant
import { NextResponse, NextRequest } from 'next/server';
export const config = { matcher: ['/pricing'] };
export function middleware(req: NextRequest) {
const existing = req.cookies.get('ab-pricing')?.value;
const bucket = existing ?? (Math.random() < 0.5 ? 'a' : 'b');
const url = req.nextUrl.clone();
url.pathname = `/pricing-${bucket}`;
const res = NextResponse.rewrite(url);
if (!existing) {
res.cookies.set('ab-pricing', bucket, { maxAge: 60 * 60 * 24 * 30 });
}
return res;
}
- Auth-gated content preview. Reading a session cookie at the edge, rewriting drafts to the preview branch, denying access without a round-trip to a Node origin.
Real latency numbers worth knowing
Rough budget on Vercel in 2026, measured from us-east-1 with a warm cache:
- Static page from CDN: 20-40ms TTFB.
- Edge Function (warm): 30-60ms TTFB on top of CDN — the function still runs before the cache for matched routes.
- Edge Function (cold): 80-150ms for the first request in a region.
- Node serverless (warm): 100-200ms.
- Node serverless (cold): 300-1500ms depending on bundle size.
If your real users are global and your function does small work, Edge cold starts can be lower than Node warm. If your function is rarely hit, Node cold is the worst case.
When Node serverless is the right answer
- OG image generation that uses
@vercel/ogwith custom fonts loaded from a CDN — works in Edge but feels nicer in Node when you need filesystem-loaded assets. - API routes that hit Prisma, Drizzle, or any ORM that does not officially support Edge runtime — most still need Node.
- Anything calling a native dependency:
sharp,puppeteer,node-canvas. These will simply not run on Edge.
When neither is right — static wins
- Article pages with content that changes on a known schedule. Pre-render at build, use ISR or on-demand revalidation for updates, skip the function entirely.
- Sitemap and robots — generate at build, serve from CDN, zero function invocations.
- Search and filter UIs where the data fits in a JSON file under 200 KB — ship it with the page and filter client-side.
Common mistakes
- Putting article pages behind an Edge Function “for personalization” — kills CDN caching and adds latency on every request.
- Importing a Node-only module into an Edge route and finding out at deploy time, not in local dev —
runtime = 'edge'should be set in dev too. - Forgetting that Edge Functions count toward your usage even on hits that 304 — middleware runs before the cache.
- Reading from a centralized database from Edge — the function is fast, but the DB round trip from random regions is not. Use a globally replicated store (Upstash, PlanetScale’s edge driver) or pre-render.
- Using Edge for OG images and hitting the 4 MB code size limit once you bundle fonts — switch to Node.
FAQ
- Are Edge Functions cheaper than Node serverless?: Per invocation, usually yes. But middleware runs on every request, so total cost can be higher if you put logic there that does not need to be there.
- Can I use Edge Functions with the Pages Router?: Yes, via
export const config = { runtime: 'edge' }in an API route or viamiddleware.ts. - What APIs are available on Edge?: Web standard APIs (fetch, Request, Response, crypto.subtle, streams). No
fs, no native modules, limitedBuffer. - Does Astro support Edge?: The
@astrojs/verceladapter has anedgemode, but most Astro sites are static and do not need it. - Will Edge make my Lighthouse score better?: Only if your TTFB was bottlenecked on a Node cold start. Static pages with good cache headers already win on Lighthouse.