Vercel can run your server logic at the edge, in regions close to users, instead of in a single serverless region. This reduces latency for auth checks, redirects, and lightweight APIs. Edge has a different runtime than Node.js, so some APIs and packages are not available.
What is the Edge?
| Concept | Description |
|---|---|
| Edge locations | Data centers worldwide (Points of Presence) |
| Edge Runtime | Lightweight V8-based runtime (not full Node.js) |
| Cold start | Milliseconds (vs hundreds of ms for Node.js) |
| Execution limit | Shorter than serverless (typically 30s) |
When a request comes in, it is handled at the nearest edge location instead of traveling to a single region.
Edge vs Node.js serverless
| Aspect | Edge Functions | Node.js Serverless |
|---|---|---|
| Location | Globally distributed | Single region |
| Cold start | ~1-5ms | ~100-500ms |
| Runtime | V8 (Web APIs) | Full Node.js |
| Memory | Limited | Up to 3GB |
| Execution time | ~30s max | ~300s max |
| npm packages | Web-compatible only | All packages |
Enabling Edge Runtime
In Route Handlers
// app/api/hello/route.ts
export const runtime = 'edge';
export async function GET(request: Request) {
return Response.json({
message: 'Hello from the edge!',
region: request.headers.get('x-vercel-ip-country'),
});
}
In Pages
// app/page.tsx
export const runtime = 'edge';
export default function Page() {
return <div>This page renders at the edge</div>;
}
In API Routes (Pages Router)
// pages/api/hello.ts
import type { NextRequest } from 'next/server';
export const config = {
runtime: 'edge',
};
export default function handler(req: NextRequest) {
return Response.json({ message: 'Hello from edge' });
}
What you can do at the edge
Read and modify headers
export const runtime = 'edge';
export async function GET(request: Request) {
const country = request.headers.get('x-vercel-ip-country');
const city = request.headers.get('x-vercel-ip-city');
return Response.json({ country, city });
}
Redirects and rewrites
import { NextResponse } from 'next/server';
export const runtime = 'edge';
export async function GET(request: Request) {
const url = new URL(request.url);
const country = request.headers.get('x-vercel-ip-country');
if (country === 'DE') {
return NextResponse.redirect(new URL('/de' + url.pathname, url));
}
return NextResponse.next();
}
Call external APIs
export const runtime = 'edge';
export async function GET() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return Response.json(data);
}
Authentication checks
import { jwtVerify } from 'jose';
export const runtime = 'edge';
export async function GET(request: Request) {
const token = request.headers.get('authorization')?.split(' ')[1];
if (!token) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const { payload } = await jwtVerify(token, secret);
return Response.json({ user: payload });
} catch {
return Response.json({ error: 'Invalid token' }, { status: 401 });
}
}
What you cannot do at the edge
Node.js APIs
// These do NOT work at the edge:
import fs from 'fs'; // No file system
import path from 'path'; // Limited
import crypto from 'crypto'; // Use Web Crypto instead
Some database drivers
// May not work:
import pg from 'pg'; // Uses Node.js APIs
import mysql from 'mysql2'; // Uses Node.js APIs
// Edge-compatible alternatives:
import { neon } from '@neondatabase/serverless'; // Neon
import { PlanetScaleDatabase } from '@planetscale/database'; // PlanetScale
Native modules
// Will not work:
import sharp from 'sharp'; // Native bindings
import bcrypt from 'bcrypt'; // Native bindings
// Use alternatives:
import { hashSync } from 'bcryptjs'; // Pure JS
Available Web APIs
The Edge Runtime supports Web Standard APIs:
| API | Description |
|---|---|
fetch |
HTTP requests |
Request / Response |
HTTP objects |
Headers |
Header manipulation |
URL / URLSearchParams |
URL parsing |
TextEncoder / TextDecoder |
Text encoding |
crypto.subtle |
Web Crypto API |
atob / btoa |
Base64 encoding |
setTimeout / setInterval |
Timers (limited) |
ReadableStream / WritableStream |
Streams |
Common patterns
Feature flags
export const runtime = 'edge';
export async function GET(request: Request) {
const userId = request.headers.get('x-user-id');
const flag = await getFeatureFlag('new-checkout', userId);
return Response.json({ enabled: flag });
}
A/B testing
import { NextResponse } from 'next/server';
export const runtime = 'edge';
export async function GET(request: Request) {
const bucket = Math.random() < 0.5 ? 'A' : 'B';
const response = NextResponse.next();
response.cookies.set('ab-bucket', bucket, { maxAge: 86400 });
return response;
}
Geo-based content
export const runtime = 'edge';
export async function GET(request: Request) {
const country = request.headers.get('x-vercel-ip-country') || 'US';
const pricing = {
US: { currency: 'USD', price: 99 },
GB: { currency: 'GBP', price: 79 },
EU: { currency: 'EUR', price: 89 },
};
return Response.json(pricing[country] || pricing.US);
}
Mixing Edge and Node.js
You can use both in one project:
app/
api/
fast/
route.ts # export const runtime = 'edge'
heavy/
route.ts # Default Node.js
middleware.ts # Always edge
Use Edge for:
- Low-latency requirements
- Simple compute
- Global availability
Use Node.js for:
- Database operations
- Heavy compute
- Node-specific packages
Debugging Edge Functions
Local development
# Edge functions work in next dev
npm run dev
Vercel CLI
vercel dev
Logs
Edge Function logs appear in Vercel's dashboard under Functions > Logs.
Summary
Edge Functions provide:
- Global distribution for low latency
- Fast cold starts (milliseconds)
- Web Standard APIs for compatibility
- Best for auth, redirects, A/B tests, lightweight APIs
Limitations:
- No Node.js-specific APIs
- Limited execution time and memory
- Some packages incompatible
The Vercel Edge Functions docs have the full API reference and examples.
