What Is Edge Computing?
Edge computing runs your code on servers geographically distributed close to your users, rather than in a centralized data center. Instead of a request traveling thousands of miles to a single origin server, it is handled by the nearest edge node — often within 50ms. This dramatically reduces latency for dynamic content.
Edge vs Origin
- Origin server: Single region, 100-300ms latency for distant users. Full Node.js runtime.
- Edge function: 200+ locations globally, 10-50ms latency. Lightweight V8 runtime.
- CDN cache: Static assets at the edge, 5-20ms. No compute, just serving cached files.
Next.js Edge Middleware
// middleware.ts — Runs at the edge before every request
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname, searchParams } = request.nextUrl;
const country = request.geo?.country || 'US';
const city = request.geo?.city || 'Unknown';
// 1. Geo-based routing for lower latency
if (pathname === '/store') {
const localizedPath = country === 'DE' ? '/store/de' :
country === 'JP' ? '/store/jp' : '/store/us';
return NextResponse.rewrite(new URL(localizedPath, request.url));
}
// 2. A/B testing at the edge (no client-side flicker)
const bucket = request.cookies.get('ab-bucket')?.value;
if (!bucket && pathname === '/') {
const newBucket = Math.random() < 0.5 ? 'control' : 'variant';
const response = NextResponse.rewrite(
new URL(`/${newBucket}`, request.url)
);
response.cookies.set('ab-bucket', newBucket, { maxAge: 60 * 60 * 24 * 30 });
return response;
}
// 3. Bot detection and rate limiting
const userAgent = request.headers.get('user-agent') || '';
if (isBot(userAgent) && pathname.startsWith('/api')) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// 4. Add performance headers
const response = NextResponse.next();
response.headers.set('X-Edge-Location', city);
response.headers.set('Server-Timing', `edge;desc="Edge Processing"`);
return response;
}
function isBot(ua: string): boolean {
return /bot|crawler|spider|scraper/i.test(ua);
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};Edge API Routes
// app/api/search/route.ts — Edge API route
import { NextRequest, NextResponse } from 'next/server';
export const runtime = 'edge'; // Run on edge network
export async function GET(request: NextRequest) {
const query = request.nextUrl.searchParams.get('q');
if (!query) {
return NextResponse.json({ results: [] });
}
// Use edge-compatible data sources
// KV store, edge database, or cached API responses
const startTime = performance.now();
const results = await searchFromEdgeStore(query);
const duration = performance.now() - startTime;
return NextResponse.json(
{ results, meta: { query, count: results.length } },
{
headers: {
'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=600',
'Server-Timing': `search;dur=${duration.toFixed(1)}`,
'CDN-Cache-Control': 'public, max-age=300',
},
}
);
}
async function searchFromEdgeStore(query: string): Promise<any[]> {
// In a real app, this would query an edge database like
// Turso, PlanetScale, Neon, or a KV store like Vercel KV
const response = await fetch(`https://search-api.example.com/search?q=${encodeURIComponent(query)}`, {
headers: { Authorization: `Bearer ${process.env.SEARCH_API_KEY}` },
next: { revalidate: 300 },
});
return response.json();
}Edge-Compatible Data Patterns
// Edge functions have limitations: no Node.js APIs, limited execution time
// Use edge-compatible alternatives:
// 1. KV Store for fast reads (Vercel KV, Cloudflare KV)
import { kv } from '@vercel/kv';
export const runtime = 'edge';
export async function GET(request: NextRequest) {
const key = request.nextUrl.searchParams.get('key');
const cached = await kv.get(key);
if (cached) return NextResponse.json(cached);
const data = await fetchFromOrigin(key);
await kv.set(key, data, { ex: 3600 }); // Cache for 1 hour
return NextResponse.json(data);
}
// 2. Edge-compatible database (Turso/libSQL)
// Ultra-low latency reads from replicas at the edge
import { createClient } from '@libsql/client/web';
const db = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});
export async function getProduct(id: string) {
const result = await db.execute({
sql: 'SELECT * FROM products WHERE id = ?',
args: [id],
});
return result.rows[0];
}Edge Computing Best Practices
- Use edge for latency-sensitive paths: Authentication, redirects, A/B tests, geo-routing
- Cache at the edge: Use CDN-Cache-Control headers for edge-level caching
- Keep functions lightweight: Edge functions have size and execution time limits
- Use edge-compatible databases: Turso, PlanetScale, Neon for global read replicas
- Measure edge vs origin: Use Server-Timing headers to compare latency