Edge Rendering
Master edge rendering — deploying server-side rendering to edge locations for minimal latency, understanding edge runtime constraints, regional deployment strategies, edge middleware patterns, data locality considerations, and platform-specific optimization for Cloudflare Workers, Vercel Edge, and Deno Deploy.
When to Use
- Users are geographically distributed and origin server latency varies by region
- TTFB is high for users far from the origin server (>200ms)
- Server-side rendering is needed but origin-only deployment adds latency
- Personalization (A/B tests, geo-targeting, localization) needs to happen before content delivery
- Authentication and authorization checks could run closer to the user
- API responses could be transformed or enriched at the edge
- Static generation is too stale but full origin SSR adds unnecessary latency
- Edge middleware is needed for redirects, rewrites, or header manipulation
- A global application needs consistent sub-100ms TTFB worldwide
- Feature flags need to be evaluated before page rendering without a client-side flash
Instructions
Understand edge versus origin architecture. Edge functions run in data centers close to the user (200+ locations) instead of a single origin:
Origin-only SSR:
User (Tokyo) → CDN → Origin (US-East) → DB → Render → Response
Network RTT: ~150ms | TTFB: ~350ms
Edge Rendering:
User (Tokyo) → Edge (Tokyo) → Render → Response
Network RTT: ~5ms | TTFB: ~50ms
Edge + Origin Data:
User (Tokyo) → Edge (Tokyo) → Origin API (US-East) → Edge Render → Response
Network RTT: ~5ms + ~150ms (data) | TTFB: ~200ms
(Still faster: user sees shell immediately via streaming)
Deploy edge functions on Cloudflare Workers. Workers run on V8 isolates with sub-millisecond cold starts:
// src/worker.ts — Cloudflare Worker
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Edge-rendered HTML
const html = await renderPage(url.pathname, {
userCountry: request.cf?.country,
userCity: request.cf?.city,
});
return new Response(html, {
headers: {
'Content-Type': 'text/html; charset=utf-8',
'Cache-Control': 'public, max-age=60, s-maxage=300',
},
});
},
};
// wrangler.toml
// name = "my-app"
// main = "src/worker.ts"
// compatibility_date = "2024-01-01"
Use Vercel Edge Runtime for Next.js. Mark routes to run on the edge instead of Node.js:
// app/api/geo/route.ts — Edge API route
export const runtime = 'edge';
export async function GET(request: Request) {
const country = request.headers.get('x-vercel-ip-country') || 'US';
const city = request.headers.get('x-vercel-ip-city') || 'Unknown';
return Response.json({
country,
city,
timestamp: Date.now(),
});
}
// middleware.ts — geo-redirects and A/B tests at the edge
// Use request.geo?.country for geo-routing, cookies for A/B persistence
// Configure matcher to exclude static assets: /((?!_next/static|favicon).*)
Handle edge runtime constraints. Edge runtimes use a limited Web API subset (no Node.js APIs):
// Available at the edge:
// - fetch(), Request, Response, Headers
// - URL, URLSearchParams, URLPattern
// - crypto.subtle, crypto.getRandomValues
// - TextEncoder, TextDecoder
// - structuredClone, atob, btoa
// - setTimeout (limited), Promises, async/await
// - Web Streams API
// NOT available at the edge:
// - fs, path, child_process (no file system)
// - Buffer (use Uint8Array instead)
// - net, http (use fetch instead)
// - Most npm packages that use Node.js APIs
// Edge-compatible alternatives:
// Database: Neon serverless, PlanetScale, Turso (HTTP-based)
// KV Store: Cloudflare KV, Vercel KV, Upstash Redis
// ORM: Drizzle (with HTTP adapter), Prisma (with Accelerate)
Implement edge caching for dynamic content. Cache rendered pages at the edge with smart invalidation:
// Cloudflare Workers — Cache API
async function handleRequest(request: Request): Promise<Response> {
const cache = caches.default;
const cacheKey = new Request(request.url, request);
// Check edge cache
let response = await cache.match(cacheKey);
if (response) {
return response;
}
// Render at the edge
const html = await renderPage(request);
response = new Response(html, {
headers: {
'Content-Type': 'text/html',
'Cache-Control': 'public, s-maxage=300', // cache at edge for 5 min
},
});
// Store in edge cache (non-blocking)
const cacheResponse = response.clone();
await cache.put(cacheKey, cacheResponse);
return response;
}
Manage data locality. Edge rendering is fast only if data access is also fast. Strategies for reducing data latency:
// Strategy 1: Edge KV for read-heavy data
// Cloudflare KV: eventually consistent, <10ms reads globally
const config = await env.CONFIG_KV.get('site-config', 'json');
// Strategy 2: Edge-local database replicas
// Turso (libSQL): read replicas in 30+ regions
// Read from local replica, write to primary
import { createClient } from '@libsql/client';
const db = createClient({
url: 'libsql://db-name-region.turso.io',
authToken: '...',
});
// Strategy 3: Cache at the edge, fetch from origin
// Best for: data that changes infrequently, high read volume
const data = await env.CACHE.get(key, 'json');
if (!data) {
const fresh = await fetch('https://origin.example.com/api/data');
await env.CACHE.put(key, await fresh.text(), { expirationTtl: 300 });
}
// Strategy 4: Smart routing — render at the edge closest to the database
// Vercel: configure function regions to match database location
// export const preferredRegion = 'iad1'; // US East, near the DB
Monitor edge function performance. Instrument with Date.now() timing, log the edge location (request.cf?.colo on Cloudflare), and always fall back to fetch(request) on error. Track cold start frequency, P99 execution time, and cache hit rates via platform analytics (Cloudflare Analytics Engine, Vercel Analytics).
Details
Edge Runtime Cold Starts
Cloudflare Workers use V8 isolates with sub-millisecond cold starts; Vercel Edge Functions ~5ms. Both are far faster than Lambda (100-1000ms). Trade-off: no file system, no native modules, limited memory (128MB), and limited CPU time (10-50ms free tier). Design edge functions to be lightweight.
Worked Example: Cloudflare Blog
Runs entirely on Workers with streaming SSR. Blog posts render from Markdown in Workers KV, cached at the edge. First request renders and caches; subsequent requests serve in <5ms globally. Webhook-based cache purging on content updates. Result: <50ms TTFB worldwide, zero origin load for reads.
Worked Example: Shopify Oxygen
Deploys Remix storefronts to Cloudflare Workers. Edge rendering takes 20-50ms, Storefront API responds in 50-100ms, yielding 70-150ms total TTFB vs 200-400ms origin-only. Stale-while-revalidate caching drops frequently-accessed pages to <10ms TTFB.
Anti-Patterns
Edge rendering with origin-only databases. If every request queries a database in US-East, the edge latency advantage is negated. Use edge-local data stores (KV, replicas) or accept the benefit is limited to non-data-dependent content.
Heavy computation at the edge. Edge runtimes have strict CPU time limits (10-50ms on free tiers). Offload image processing and heavy transformations to origin functions. Use the edge for lightweight rendering, routing, and personalization.
Not falling back to origin on edge failure. Always implement a fallback path to the origin server for when edge functions fail due to platform issues or resource limits.
Deploying globally when data is in one region. If most traffic is regional and the DB is in US-East, 200+ edge locations add no benefit. Use preferredRegion to deploy near the database for data-heavy pages.
Source
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- Edge functions achieve <100ms TTFB for users in the primary geographic region.
- Edge runtime constraints are respected (no Node.js-only APIs in edge functions).
- Data access strategy accounts for edge-to-origin latency (KV, replicas, or regional deployment).
- Edge caching is configured with appropriate TTLs and invalidation mechanisms.
- Fallback to origin is implemented for edge function failures.
1---2name: perf-edge-rendering3description: Edge Rendering4---5# Edge Rendering67> Master edge rendering — deploying server-side rendering to edge locations for minimal latency, understanding edge runtime constraints, regional deployment strategies, edge middleware patterns, data locality considerations, and platform-specific optimization for Cloudflare Workers, Vercel Edge, and Deno Deploy.89## When to Use1011- Users are geographically distributed and origin server latency varies by region12- TTFB is high for users far from the origin server (>200ms)13- Server-side rendering is needed but origin-only deployment adds latency14- Personalization (A/B tests, geo-targeting, localization) needs to happen before content delivery15- Authentication and authorization checks could run closer to the user16- API responses could be transformed or enriched at the edge17- Static generation is too stale but full origin SSR adds unnecessary latency18- Edge middleware is needed for redirects, rewrites, or header manipulation19- A global application needs consistent sub-100ms TTFB worldwide20- Feature flags need to be evaluated before page rendering without a client-side flash2122## Instructions23241. **Understand edge versus origin architecture.** Edge functions run in data centers close to the user (200+ locations) instead of a single origin:2526 ```27 Origin-only SSR:28 User (Tokyo) → CDN → Origin (US-East) → DB → Render → Response29 Network RTT: ~150ms | TTFB: ~350ms3031 Edge Rendering:32 User (Tokyo) → Edge (Tokyo) → Render → Response33 Network RTT: ~5ms | TTFB: ~50ms3435 Edge + Origin Data:36 User (Tokyo) → Edge (Tokyo) → Origin API (US-East) → Edge Render → Response37 Network RTT: ~5ms + ~150ms (data) | TTFB: ~200ms38 (Still faster: user sees shell immediately via streaming)39 ```40412. **Deploy edge functions on Cloudflare Workers.** Workers run on V8 isolates with sub-millisecond cold starts:4243 ```typescript44 // src/worker.ts — Cloudflare Worker45 export default {46 async fetch(request: Request, env: Env): Promise<Response> {47 const url = new URL(request.url);4849 // Edge-rendered HTML50 const html = await renderPage(url.pathname, {51 userCountry: request.cf?.country,52 userCity: request.cf?.city,53 });5455 return new Response(html, {56 headers: {57 'Content-Type': 'text/html; charset=utf-8',58 'Cache-Control': 'public, max-age=60, s-maxage=300',59 },60 });61 },62 };6364 // wrangler.toml65 // name = "my-app"66 // main = "src/worker.ts"67 // compatibility_date = "2024-01-01"68 ```69703. **Use Vercel Edge Runtime for Next.js.** Mark routes to run on the edge instead of Node.js:7172 ```typescript73 // app/api/geo/route.ts — Edge API route74 export const runtime = 'edge';7576 export async function GET(request: Request) {77 const country = request.headers.get('x-vercel-ip-country') || 'US';78 const city = request.headers.get('x-vercel-ip-city') || 'Unknown';7980 return Response.json({81 country,82 city,83 timestamp: Date.now(),84 });85 }8687 // middleware.ts — geo-redirects and A/B tests at the edge88 // Use request.geo?.country for geo-routing, cookies for A/B persistence89 // Configure matcher to exclude static assets: /((?!_next/static|favicon).*)90 ```91924. **Handle edge runtime constraints.** Edge runtimes use a limited Web API subset (no Node.js APIs):9394 ```typescript95 // Available at the edge:96 // - fetch(), Request, Response, Headers97 // - URL, URLSearchParams, URLPattern98 // - crypto.subtle, crypto.getRandomValues99 // - TextEncoder, TextDecoder100 // - structuredClone, atob, btoa101 // - setTimeout (limited), Promises, async/await102 // - Web Streams API103104 // NOT available at the edge:105 // - fs, path, child_process (no file system)106 // - Buffer (use Uint8Array instead)107 // - net, http (use fetch instead)108 // - Most npm packages that use Node.js APIs109110 // Edge-compatible alternatives:111 // Database: Neon serverless, PlanetScale, Turso (HTTP-based)112 // KV Store: Cloudflare KV, Vercel KV, Upstash Redis113 // ORM: Drizzle (with HTTP adapter), Prisma (with Accelerate)114 ```1151165. **Implement edge caching for dynamic content.** Cache rendered pages at the edge with smart invalidation:117118 ```typescript119 // Cloudflare Workers — Cache API120 async function handleRequest(request: Request): Promise<Response> {121 const cache = caches.default;122 const cacheKey = new Request(request.url, request);123124 // Check edge cache125 let response = await cache.match(cacheKey);126 if (response) {127 return response;128 }129130 // Render at the edge131 const html = await renderPage(request);132 response = new Response(html, {133 headers: {134 'Content-Type': 'text/html',135 'Cache-Control': 'public, s-maxage=300', // cache at edge for 5 min136 },137 });138139 // Store in edge cache (non-blocking)140 const cacheResponse = response.clone();141 await cache.put(cacheKey, cacheResponse);142143 return response;144 }145 ```1461476. **Manage data locality.** Edge rendering is fast only if data access is also fast. Strategies for reducing data latency:148149 ```typescript150 // Strategy 1: Edge KV for read-heavy data151 // Cloudflare KV: eventually consistent, <10ms reads globally152 const config = await env.CONFIG_KV.get('site-config', 'json');153154 // Strategy 2: Edge-local database replicas155 // Turso (libSQL): read replicas in 30+ regions156 // Read from local replica, write to primary157 import { createClient } from '@libsql/client';158 const db = createClient({159 url: 'libsql://db-name-region.turso.io',160 authToken: '...',161 });162163 // Strategy 3: Cache at the edge, fetch from origin164 // Best for: data that changes infrequently, high read volume165 const data = await env.CACHE.get(key, 'json');166 if (!data) {167 const fresh = await fetch('https://origin.example.com/api/data');168 await env.CACHE.put(key, await fresh.text(), { expirationTtl: 300 });169 }170171 // Strategy 4: Smart routing — render at the edge closest to the database172 // Vercel: configure function regions to match database location173 // export const preferredRegion = 'iad1'; // US East, near the DB174 ```1751767. **Monitor edge function performance.** Instrument with `Date.now()` timing, log the edge location (`request.cf?.colo` on Cloudflare), and always fall back to `fetch(request)` on error. Track cold start frequency, P99 execution time, and cache hit rates via platform analytics (Cloudflare Analytics Engine, Vercel Analytics).177178## Details179180### Edge Runtime Cold Starts181182Cloudflare Workers use V8 isolates with sub-millisecond cold starts; Vercel Edge Functions ~5ms. Both are far faster than Lambda (100-1000ms). Trade-off: no file system, no native modules, limited memory (128MB), and limited CPU time (10-50ms free tier). Design edge functions to be lightweight.183184### Worked Example: Cloudflare Blog185186Runs entirely on Workers with streaming SSR. Blog posts render from Markdown in Workers KV, cached at the edge. First request renders and caches; subsequent requests serve in <5ms globally. Webhook-based cache purging on content updates. Result: <50ms TTFB worldwide, zero origin load for reads.187188### Worked Example: Shopify Oxygen189190Deploys Remix storefronts to Cloudflare Workers. Edge rendering takes 20-50ms, Storefront API responds in 50-100ms, yielding 70-150ms total TTFB vs 200-400ms origin-only. Stale-while-revalidate caching drops frequently-accessed pages to <10ms TTFB.191192### Anti-Patterns193194**Edge rendering with origin-only databases.** If every request queries a database in US-East, the edge latency advantage is negated. Use edge-local data stores (KV, replicas) or accept the benefit is limited to non-data-dependent content.195196**Heavy computation at the edge.** Edge runtimes have strict CPU time limits (10-50ms on free tiers). Offload image processing and heavy transformations to origin functions. Use the edge for lightweight rendering, routing, and personalization.197198**Not falling back to origin on edge failure.** Always implement a fallback path to the origin server for when edge functions fail due to platform issues or resource limits.199200**Deploying globally when data is in one region.** If most traffic is regional and the DB is in US-East, 200+ edge locations add no benefit. Use `preferredRegion` to deploy near the database for data-heavy pages.201202## Source203204- Cloudflare Workers — https://developers.cloudflare.com/workers/205- Vercel Edge Functions — https://vercel.com/docs/functions/edge-functions206- Deno Deploy — https://deno.com/deploy207- web.dev: Edge Rendering — https://web.dev/articles/rendering-on-the-web#edge_rendering208209## Process2102111. Read the instructions and examples in this document.2122. Apply the patterns to your implementation, adapting to your specific context.2133. Verify your implementation against the details and edge cases listed above.214215## Harness Integration216217- **Type:** knowledge — this skill is a reference document, not a procedural workflow.218- **No tools or state** — consumed as context by other skills and agents.219220## Success Criteria221222- Edge functions achieve <100ms TTFB for users in the primary geographic region.223- Edge runtime constraints are respected (no Node.js-only APIs in edge functions).224- Data access strategy accounts for edge-to-origin latency (KV, replicas, or regional deployment).225- Edge caching is configured with appropriate TTLs and invalidation mechanisms.226- Fallback to origin is implemented for edge function failures.