Serverless Edge Computing: The 2026 Revolution in Web Performance
AI & Development

Serverless Edge Computing: The 2026 Revolution in Web Performance

Edge computing is revolutionizing web performance. Learn how to leverage Cloudflare Workers, Vercel Edge Functions, and Deno Deploy for lightning-fast applications.

Feb 03, 2026
14 min read
Serverless Edge Computing: The 2026 Revolution in Web Performance

Edge computing promised to bring computation closer to users. In 2026, it's delivering on that promise in ways that are fundamentally changing how we build web applications. Here's what you need to know about the edge revolution.

Related reading: Check out our guides on WebAssembly performance and React optimization for more performance insights.

The Edge Computing Revolution#

What Changed in 2026#

Global edge networks now span 300+ locations worldwide, putting compute within 50ms of 95% of internet users.

JavaScript runtime standardization with Web APIs means code runs consistently across edge platforms.

Cold start elimination - edge functions now start in under 1ms, making them viable for real-time applications.

Cost efficiency - edge computing is now 60% cheaper than traditional cloud for many workloads.

Why Edge Computing Matters#

Latency reduction: 50-200ms improvement in response times Improved user experience: Faster page loads and interactions Global scalability: Automatic scaling across regions Reduced infrastructure costs: Pay only for what you use Enhanced security: Distributed architecture reduces attack surface

Major Edge Computing Platforms#

1. Cloudflare Workers#

Best for: High-performance APIs, middleware, and real-time applications

// Basic Cloudflare Worker
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // Handle different routes
    if (url.pathname === '/api/users') {
      return handleUsers(request, env);
    }
    
    if (url.pathname.startsWith('/api/auth')) {
      return handleAuth(request, env);
    }
    
    // Default response
    return new Response('Hello from the edge!', {
      headers: { 'Content-Type': 'text/plain' },
    });
  },
};

// User management with D1 database
async function handleUsers(request, env) {
  const { method } = request;
  
  switch (method) {
    case 'GET':
      const users = await env.DB.prepare('SELECT * FROM users').all();
      return Response.json(users.results);
      
    case 'POST':
      const userData = await request.json();
      const result = await env.DB.prepare(
        'INSERT INTO users (name, email) VALUES (?, ?)'
      ).bind(userData.name, userData.email).run();
      
      return Response.json({ id: result.meta.last_row_id });
      
    default:
      return new Response('Method not allowed', { status: 405 });
  }
}

// Authentication with JWT
async function handleAuth(request, env) {
  const url = new URL(request.url);
  
  if (url.pathname === '/api/auth/login') {
    const { email, password } = await request.json();
    
    // Verify credentials (simplified)
    const user = await env.DB.prepare(
      'SELECT * FROM users WHERE email = ?'
    ).bind(email).first();
    
    if (user && await verifyPassword(password, user.password_hash)) {
      const token = await generateJWT(user, env.JWT_SECRET);
      
      return Response.json({ token, user: { id: user.id, email: user.email } });
    }
    
    return new Response('Invalid credentials', { status: 401 });
  }
  
  return new Response('Not found', { status: 404 });
}

// JWT utilities
async function generateJWT(user, secret) {
  const header = { alg: 'HS256', typ: 'JWT' };
  const payload = {
    sub: user.id,
    email: user.email,
    exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour
  };
  
  const encoder = new TextEncoder();
  const data = encoder.encode(
    btoa(JSON.stringify(header)) + '.' + btoa(JSON.stringify(payload))
  );
  
  const key = await crypto.subtle.importKey(
    'raw',
    encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );
  
  const signature = await crypto.subtle.sign('HMAC', key, data);
  const signatureBase64 = btoa(String.fromCharCode(...new Uint8Array(signature)));
  
  return btoa(JSON.stringify(header)) + '.' + 
         btoa(JSON.stringify(payload)) + '.' + 
         signatureBase64;
}

Advanced Cloudflare Workers patterns:

// Request/Response transformation
export default {
  async fetch(request, env, ctx) {
    // Add security headers
    const response = await fetch(request);
    const newResponse = new Response(response.body, response);
    
    newResponse.headers.set('X-Frame-Options', 'DENY');
    newResponse.headers.set('X-Content-Type-Options', 'nosniff');
    newResponse.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    
    return newResponse;
  },
};

// A/B testing at the edge
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // Determine variant based on user
    const userId = request.headers.get('X-User-ID');
    const variant = getUserVariant(userId);
    
    if (variant === 'B' && url.pathname === '/') {
      // Serve different version
      return fetch(request.url.replace('/', '/variant-b/'));
    }
    
    return fetch(request);
  },
};

function getUserVariant(userId) {
  if (!userId) return 'A';
  
  // Simple hash-based assignment
  const hash = Array.from(userId).reduce((a, b) => {
    a = ((a << 5) - a) + b.charCodeAt(0);
    return a & a;
  }, 0);
  
  return Math.abs(hash) % 2 === 0 ? 'A' : 'B';
}

// Caching with KV storage
export default {
  async fetch(request, env, ctx) {
    const cacheKey = new URL(request.url).pathname;
    
    // Try to get from cache first
    const cached = await env.CACHE.get(cacheKey);
    if (cached) {
      return new Response(cached, {
        headers: { 'Content-Type': 'application/json' },
      });
    }
    
    // Fetch from origin
    const response = await fetch(request);
    const data = await response.text();
    
    // Cache for 1 hour
    ctx.waitUntil(env.CACHE.put(cacheKey, data, { expirationTtl: 3600 }));
    
    return new Response(data, response);
  },
};

2. Vercel Edge Functions#

Best for: Next.js applications, middleware, and personalization

// Vercel Edge Function
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  
  // Geolocation-based routing
  const country = request.geo?.country || 'US';
  
  if (pathname === '/') {
    if (country === 'DE') {
      return NextResponse.redirect(new URL('/de', request.url));
    }
    if (country === 'FR') {
      return NextResponse.redirect(new URL('/fr', request.url));
    }
  }
  
  // A/B testing
  if (pathname.startsWith('/product')) {
    const variant = getVariant(request);
    const response = NextResponse.next();
    
    response.cookies.set('variant', variant);
    response.headers.set('X-Variant', variant);
    
    return response;
  }
  
  return NextResponse.next();
}

function getVariant(request: NextRequest) {
  // Check existing cookie
  const existingVariant = request.cookies.get('variant')?.value;
  if (existingVariant) return existingVariant;
  
  // Assign based on IP hash
  const ip = request.ip || request.headers.get('x-forwarded-for') || 'unknown';
  const hash = simpleHash(ip);
  
  return hash % 2 === 0 ? 'A' : 'B';
}

function simpleHash(str: string): number {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash; // Convert to 32-bit integer
  }
  return Math.abs(hash);
}

export const config = {
  matcher: ['/', '/product/:path*'],
};

// API Route at the edge
// pages/api/edge/user.ts
import type { NextRequest } from 'next/server';

export const config = {
  runtime: 'edge',
};

export default async function handler(req: NextRequest) {
  const { method } = req;
  const url = new URL(req.url);
  const userId = url.searchParams.get('id');
  
  if (method === 'GET' && userId) {
    // Fetch user data from edge-optimized database
    const userData = await fetchUserFromEdge(userId);
    
    return new Response(JSON.stringify(userData), {
      status: 200,
      headers: {
        'Content-Type': 'application/json',
        'Cache-Control': 's-maxage=60, stale-while-revalidate=300',
      },
    });
  }
  
  return new Response('Method not allowed', { status: 405 });
}

async function fetchUserFromEdge(userId: string) {
  // Simulate edge database query
  return {
    id: userId,
    name: 'John Doe',
    email: 'john@example.com',
    lastSeen: new Date().toISOString(),
  };
}

3. Deno Deploy#

Best for: TypeScript-first applications, modern web standards

// Deno Deploy function
import { serve } from "https://deno.land/std@0.208.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

const supabase = createClient(
  Deno.env.get("SUPABASE_URL")!,
  Deno.env.get("SUPABASE_ANON_KEY")!
);

async function handler(req: Request): Promise<Response> {
  const url = new URL(req.url);
  const { pathname, searchParams } = url;
  
  // CORS headers
  const corsHeaders = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
  };
  
  if (req.method === "OPTIONS") {
    return new Response(null, { headers: corsHeaders });
  }
  
  try {
    if (pathname === "/api/posts") {
      return await handlePosts(req, corsHeaders);
    }
    
    if (pathname.startsWith("/api/posts/")) {
      const postId = pathname.split("/").pop();
      return await handlePost(req, postId!, corsHeaders);
    }
    
    if (pathname === "/api/search") {
      const query = searchParams.get("q");
      return await handleSearch(query, corsHeaders);
    }
    
    return new Response("Not Found", { 
      status: 404, 
      headers: corsHeaders 
    });
    
  } catch (error) {
    console.error("Error:", error);
    return new Response("Internal Server Error", { 
      status: 500, 
      headers: corsHeaders 
    });
  }
}

async function handlePosts(req: Request, corsHeaders: Record<string, string>) {
  if (req.method === "GET") {
    const { data, error } = await supabase
      .from("posts")
      .select("*")
      .order("created_at", { ascending: false })
      .limit(20);
    
    if (error) throw error;
    
    return new Response(JSON.stringify(data), {
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }
  
  if (req.method === "POST") {
    const postData = await req.json();
    
    const { data, error } = await supabase
      .from("posts")
      .insert([postData])
      .select()
      .single();
    
    if (error) throw error;
    
    return new Response(JSON.stringify(data), {
      status: 201,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }
  
  return new Response("Method Not Allowed", { 
    status: 405, 
    headers: corsHeaders 
  });
}

async function handlePost(req: Request, postId: string, corsHeaders: Record<string, string>) {
  if (req.method === "GET") {
    const { data, error } = await supabase
      .from("posts")
      .select("*")
      .eq("id", postId)
      .single();
    
    if (error) {
      if (error.code === "PGRST116") {
        return new Response("Not Found", { 
          status: 404, 
          headers: corsHeaders 
        });
      }
      throw error;
    }
    
    return new Response(JSON.stringify(data), {
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }
  
  return new Response("Method Not Allowed", { 
    status: 405, 
    headers: corsHeaders 
  });
}

async function handleSearch(query: string | null, corsHeaders: Record<string, string>) {
  if (!query) {
    return new Response("Query parameter 'q' is required", { 
      status: 400, 
      headers: corsHeaders 
    });
  }
  
  const { data, error } = await supabase
    .from("posts")
    .select("*")
    .textSearch("title", query)
    .limit(10);
  
  if (error) throw error;
  
  return new Response(JSON.stringify(data), {
    headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
}

serve(handler);

// WebSocket support in Deno Deploy
serve((req) => {
  const upgrade = req.headers.get("upgrade") || "";
  
  if (upgrade.toLowerCase() !== "websocket") {
    return new Response("Expected websocket", { status: 426 });
  }
  
  const { socket, response } = Deno.upgradeWebSocket(req);
  
  socket.addEventListener("open", () => {
    console.log("WebSocket connected");
    socket.send("Welcome to Deno Deploy WebSocket!");
  });
  
  socket.addEventListener("message", (event) => {
    console.log("Received:", event.data);
    
    // Echo the message back
    socket.send(`Echo: ${event.data}`);
  });
  
  socket.addEventListener("close", () => {
    console.log("WebSocket disconnected");
  });
  
  return response;
});

Edge Computing Patterns#

1. Edge-Side Includes (ESI)#

// Cloudflare Worker for ESI
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    let html = await response.text();
    
    // Process ESI tags
    html = await processESI(html, request, env);
    
    return new Response(html, {
      headers: { 'Content-Type': 'text/html' },
    });
  },
};

async function processESI(html, request, env) {
  const esiRegex = /<esi:include src="([^"]+)"[^>]*>/g;
  
  const promises = [];
  const matches = [];
  let match;
  
  while ((match = esiRegex.exec(html)) !== null) {
    matches.push(match);
    promises.push(fetchFragment(match[1], request, env));
  }
  
  const fragments = await Promise.all(promises);
  
  matches.forEach((match, index) => {
    html = html.replace(match[0], fragments[index]);
  });
  
  return html;
}

async function fetchFragment(src, request, env) {
  try {
    const fragmentUrl = new URL(src, request.url);
    const response = await fetch(fragmentUrl.toString());
    return await response.text();
  } catch (error) {
    console.error('ESI fragment error:', error);
    return '<!-- ESI fragment failed to load -->';
  }
}

2. Edge Caching with Stale-While-Revalidate#

// Advanced caching strategy
export default {
  async fetch(request, env, ctx) {
    const cache = caches.default;
    const cacheKey = new Request(request.url, request);
    
    // Try cache first
    let response = await cache.match(cacheKey);
    
    if (response) {
      const age = Date.now() - new Date(response.headers.get('Date')).getTime();
      const maxAge = 300000; // 5 minutes
      const staleAge = 3600000; // 1 hour
      
      if (age < maxAge) {
        // Fresh cache hit
        return response;
      } else if (age < staleAge) {
        // Stale but acceptable, revalidate in background
        ctx.waitUntil(revalidateCache(request, env, cache, cacheKey));
        return response;
      }
    }
    
    // Cache miss or too stale, fetch fresh
    response = await fetchAndCache(request, env, cache, cacheKey);
    return response;
  },
};

async function fetchAndCache(request, env, cache, cacheKey) {
  const response = await fetch(request);
  const responseToCache = response.clone();
  
  // Add cache headers
  responseToCache.headers.set('Date', new Date().toISOString());
  responseToCache.headers.set('Cache-Control', 'public, max-age=300');
  
  // Cache the response
  await cache.put(cacheKey, responseToCache);
  
  return response;
}

async function revalidateCache(request, env, cache, cacheKey) {
  try {
    await fetchAndCache(request, env, cache, cacheKey);
  } catch (error) {
    console.error('Background revalidation failed:', error);
  }
}

3. Edge Authentication#

// JWT verification at the edge
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // Public routes
    if (url.pathname === '/login' || url.pathname === '/register') {
      return fetch(request);
    }
    
    // Protected routes
    if (url.pathname.startsWith('/api/')) {
      const authResult = await verifyAuth(request, env);
      
      if (!authResult.valid) {
        return new Response('Unauthorized', { status: 401 });
      }
      
      // Add user info to request headers
      const modifiedRequest = new Request(request);
      modifiedRequest.headers.set('X-User-ID', authResult.userId);
      modifiedRequest.headers.set('X-User-Role', authResult.role);
      
      return fetch(modifiedRequest);
    }
    
    return fetch(request);
  },
};

async function verifyAuth(request, env) {
  const authHeader = request.headers.get('Authorization');
  
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return { valid: false };
  }
  
  const token = authHeader.substring(7);
  
  try {
    const payload = await verifyJWT(token, env.JWT_SECRET);
    
    return {
      valid: true,
      userId: payload.sub,
      role: payload.role || 'user',
    };
  } catch (error) {
    return { valid: false };
  }
}

async function verifyJWT(token, secret) {
  const [headerB64, payloadB64, signatureB64] = token.split('.');
  
  if (!headerB64 || !payloadB64 || !signatureB64) {
    throw new Error('Invalid token format');
  }
  
  const encoder = new TextEncoder();
  const data = encoder.encode(`${headerB64}.${payloadB64}`);
  
  const key = await crypto.subtle.importKey(
    'raw',
    encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['verify']
  );
  
  const signature = Uint8Array.from(atob(signatureB64), c => c.charCodeAt(0));
  
  const isValid = await crypto.subtle.verify('HMAC', key, signature, data);
  
  if (!isValid) {
    throw new Error('Invalid signature');
  }
  
  const payload = JSON.parse(atob(payloadB64));
  
  if (payload.exp && payload.exp < Date.now() / 1000) {
    throw new Error('Token expired');
  }
  
  return payload;
}

Performance Optimization at the Edge#

1. Request/Response Optimization#

// Response compression and optimization
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    
    // Skip optimization for non-HTML responses
    const contentType = response.headers.get('Content-Type') || '';
    if (!contentType.includes('text/html')) {
      return response;
    }
    
    let html = await response.text();
    
    // Minify HTML
    html = minifyHTML(html);
    
    // Optimize images
    html = await optimizeImages(html, request);
    
    // Add performance hints
    html = addPerformanceHints(html);
    
    const optimizedResponse = new Response(html, {
      status: response.status,
      statusText: response.statusText,
      headers: response.headers,
    });
    
    // Add compression
    if (request.headers.get('Accept-Encoding')?.includes('gzip')) {
      const compressed = await gzipCompress(html);
      optimizedResponse.headers.set('Content-Encoding', 'gzip');
      return new Response(compressed, optimizedResponse);
    }
    
    return optimizedResponse;
  },
};

function minifyHTML(html) {
  return html
    .replace(/\s+/g, ' ')
    .replace(/>\s+</g, '><')
    .trim();
}

async function optimizeImages(html, request) {
  const imgRegex = /<img([^>]+)src="([^"]+)"([^>]*)>/g;
  
  return html.replace(imgRegex, (match, before, src, after) => {
    // Convert to WebP if supported
    const acceptsWebP = request.headers.get('Accept')?.includes('image/webp');
    
    if (acceptsWebP && !src.includes('.webp')) {
      const webpSrc = src.replace(/\.(jpg|jpeg|png)$/i, '.webp');
      return `<img${before}src="${webpSrc}"${after}>`;
    }
    
    return match;
  });
}

function addPerformanceHints(html) {
  // Add preload hints for critical resources
  const head = html.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
  if (head) {
    const preloads = `
      <link rel="preload" href="/critical.css" as="style">
      <link rel="preload" href="/critical.js" as="script">
      <link rel="dns-prefetch" href="//api.example.com">
    `;
    
    const newHead = head[0].replace('</head>', `${preloads}</head>`);
    html = html.replace(head[0], newHead);
  }
  
  return html;
}

async function gzipCompress(text) {
  const stream = new CompressionStream('gzip');
  const writer = stream.writable.getWriter();
  const reader = stream.readable.getReader();
  
  writer.write(new TextEncoder().encode(text));
  writer.close();
  
  const chunks = [];
  let done = false;
  
  while (!done) {
    const { value, done: readerDone } = await reader.read();
    done = readerDone;
    if (value) chunks.push(value);
  }
  
  return new Uint8Array(chunks.reduce((acc, chunk) => [...acc, ...chunk], []));
}

2. Edge Database Patterns#

// Distributed caching with eventual consistency
class EdgeCache {
  constructor(env) {
    this.kv = env.CACHE_KV;
    this.durable = env.CACHE_DURABLE;
  }
  
  async get(key, options = {}) {
    const { fallbackToOrigin = true, maxAge = 3600 } = options;
    
    // Try KV first (fastest)
    const kvValue = await this.kv.get(key, 'json');
    if (kvValue && this.isValid(kvValue, maxAge)) {
      return kvValue.data;
    }
    
    // Try Durable Object (consistent)
    if (this.durable) {
      const durableValue = await this.getDurableValue(key);
      if (durableValue && this.isValid(durableValue, maxAge)) {
        // Update KV cache
        this.kv.put(key, JSON.stringify(durableValue));
        return durableValue.data;
      }
    }
    
    // Fallback to origin
    if (fallbackToOrigin) {
      const originValue = await this.getFromOrigin(key);
      if (originValue) {
        await this.set(key, originValue);
        return originValue;
      }
    }
    
    return null;
  }
  
  async set(key, value, ttl = 3600) {
    const cacheEntry = {
      data: value,
      timestamp: Date.now(),
      ttl: ttl * 1000,
    };
    
    // Store in both KV and Durable Object
    await Promise.all([
      this.kv.put(key, JSON.stringify(cacheEntry), { expirationTtl: ttl }),
      this.setDurableValue(key, cacheEntry),
    ]);
  }
  
  isValid(entry, maxAge) {
    const age = Date.now() - entry.timestamp;
    return age < (maxAge * 1000);
  }
  
  async getDurableValue(key) {
    // Implementation depends on Durable Object setup
    const id = this.durable.idFromName(key);
    const obj = this.durable.get(id);
    const response = await obj.fetch(`http://cache/${key}`);
    
    if (response.ok) {
      return await response.json();
    }
    
    return null;
  }
  
  async setDurableValue(key, value) {
    const id = this.durable.idFromName(key);
    const obj = this.durable.get(id);
    
    await obj.fetch(`http://cache/${key}`, {
      method: 'PUT',
      body: JSON.stringify(value),
    });
  }
  
  async getFromOrigin(key) {
    try {
      const response = await fetch(`https://api.example.com/data/${key}`);
      if (response.ok) {
        return await response.json();
      }
    } catch (error) {
      console.error('Origin fetch failed:', error);
    }
    
    return null;
  }
}

// Usage in Worker
export default {
  async fetch(request, env, ctx) {
    const cache = new EdgeCache(env);
    const url = new URL(request.url);
    const key = url.pathname.substring(1);
    
    if (request.method === 'GET') {
      const data = await cache.get(key);
      
      if (data) {
        return Response.json(data);
      }
      
      return new Response('Not found', { status: 404 });
    }
    
    if (request.method === 'POST') {
      const data = await request.json();
      await cache.set(key, data);
      
      return Response.json({ success: true });
    }
    
    return new Response('Method not allowed', { status: 405 });
  },
};

Monitoring and Debugging#

1. Edge Function Observability#

// Comprehensive logging and monitoring
class EdgeLogger {
  constructor(env) {
    this.env = env;
    this.requestId = crypto.randomUUID();
  }
  
  log(level, message, data = {}) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      requestId: this.requestId,
      data,
      edge: {
        colo: this.env.CF_RAY?.split('-')[1] || 'unknown',
        country: this.env.CF_IPCOUNTRY || 'unknown',
      },
    };
    
    console.log(JSON.stringify(logEntry));
    
    // Send to external logging service
    if (this.env.LOG_ENDPOINT) {
      fetch(this.env.LOG_ENDPOINT, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(logEntry),
      }).catch(err => console.error('Logging failed:', err));
    }
  }
  
  info(message, data) { this.log('info', message, data); }
  warn(message, data) { this.log('warn', message, data); }
  error(message, data) { this.log('error', message, data); }
}

// Performance monitoring
class EdgeMetrics {
  constructor() {
    this.startTime = Date.now();
    this.metrics = new Map();
  }
  
  mark(name) {
    this.metrics.set(name, Date.now() - this.startTime);
  }
  
  measure(name, startMark, endMark) {
    const start = this.metrics.get(startMark) || 0;
    const end = this.metrics.get(endMark) || Date.now() - this.startTime;
    this.metrics.set(name, end - start);
  }
  
  getMetrics() {
    return Object.fromEntries(this.metrics);
  }
}

// Usage in Worker
export default {
  async fetch(request, env, ctx) {
    const logger = new EdgeLogger(env);
    const metrics = new EdgeMetrics();
    
    try {
      logger.info('Request started', {
        url: request.url,
        method: request.method,
        userAgent: request.headers.get('User-Agent'),
      });
      
      metrics.mark('request-start');
      
      // Process request
      const response = await processRequest(request, env, logger, metrics);
      
      metrics.mark('request-end');
      metrics.measure('total-time', 'request-start', 'request-end');
      
      logger.info('Request completed', {
        status: response.status,
        metrics: metrics.getMetrics(),
      });
      
      return response;
      
    } catch (error) {
      logger.error('Request failed', {
        error: error.message,
        stack: error.stack,
      });
      
      return new Response('Internal Server Error', { status: 500 });
    }
  },
};

async function processRequest(request, env, logger, metrics) {
  const url = new URL(request.url);
  
  if (url.pathname === '/api/health') {
    return Response.json({ status: 'ok', timestamp: Date.now() });
  }
  
  metrics.mark('database-start');
  const data = await fetchData(url.pathname, env, logger);
  metrics.mark('database-end');
  metrics.measure('database-time', 'database-start', 'database-end');
  
  return Response.json(data);
}

async function fetchData(path, env, logger) {
  try {
    const response = await fetch(`${env.API_BASE}${path}`);
    
    if (!response.ok) {
      logger.warn('API request failed', {
        status: response.status,
        path,
      });
    }
    
    return await response.json();
  } catch (error) {
    logger.error('Data fetch failed', { error: error.message, path });
    throw error;
  }
}

Cost Optimization Strategies#

1. Request Routing and Load Balancing#

// Intelligent request routing
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // Route based on request characteristics
    const route = determineRoute(request, env);
    
    switch (route.type) {
      case 'static':
        return handleStatic(request, route);
      case 'api':
        return handleAPI(request, route, env);
      case 'compute':
        return handleCompute(request, route, env);
      default:
        return new Response('Not found', { status: 404 });
    }
  },
};

function determineRoute(request, env) {
  const url = new URL(request.url);
  const { pathname } = url;
  
  // Static assets
  if (pathname.match(/\.(css|js|png|jpg|svg|ico)$/)) {
    return { type: 'static', cacheTtl: 86400 };
  }
  
  // API endpoints
  if (pathname.startsWith('/api/')) {
    const complexity = estimateComplexity(pathname, request);
    
    if (complexity < 100) {
      return { type: 'api', target: 'edge' };
    } else {
      return { type: 'api', target: 'origin' };
    }
  }
  
  // Compute-intensive operations
  if (pathname.startsWith('/compute/')) {
    return { type: 'compute', target: 'worker' };
  }
  
  return { type: 'unknown' };
}

function estimateComplexity(pathname, request) {
  let complexity = 0;
  
  // Database operations
  if (pathname.includes('/search')) complexity += 50;
  if (pathname.includes('/aggregate')) complexity += 100;
  if (pathname.includes('/report')) complexity += 200;
  
  // Request size
  const contentLength = parseInt(request.headers.get('Content-Length') || '0');
  complexity += Math.floor(contentLength / 1000);
  
  return complexity;
}

async function handleStatic(request, route) {
  const response = await fetch(request);
  
  // Add aggressive caching for static assets
  const newResponse = new Response(response.body, response);
  newResponse.headers.set('Cache-Control', `public, max-age=${route.cacheTtl}`);
  
  return newResponse;
}

async function handleAPI(request, route, env) {
  if (route.target === 'edge') {
    // Handle at edge
    return processAtEdge(request, env);
  } else {
    // Forward to origin with optimizations
    return forwardToOrigin(request, env);
  }
}

async function processAtEdge(request, env) {
  // Simple operations that can be handled at edge
  const url = new URL(request.url);
  
  if (url.pathname === '/api/time') {
    return Response.json({ timestamp: Date.now() });
  }
  
  if (url.pathname === '/api/geo') {
    return Response.json({
      country: request.cf?.country || 'unknown',
      city: request.cf?.city || 'unknown',
      timezone: request.cf?.timezone || 'unknown',
    });
  }
  
  return new Response('Not implemented', { status: 501 });
}

async function forwardToOrigin(request, env) {
  // Add request optimization
  const optimizedRequest = new Request(request);
  optimizedRequest.headers.set('X-Edge-Processing', 'true');
  optimizedRequest.headers.set('X-Request-ID', crypto.randomUUID());
  
  return fetch(optimizedRequest);
}

Frequently Asked Questions#

Q: When should I use edge computing vs traditional cloud? A: Use edge computing for latency-sensitive operations, global applications, and simple to moderate complexity workloads. Traditional cloud is better for complex computations, large databases, and legacy systems.

Q: How do I handle state in edge functions? A: Use distributed storage like Cloudflare KV, Durable Objects, or external databases. Avoid local state since edge functions are stateless and distributed.

Q: What about cold starts? A: Modern edge platforms have virtually eliminated cold starts (< 1ms). This is one of the key advantages over traditional serverless functions.

Q: How do I debug edge functions? A: Use structured logging, distributed tracing, and platform-specific tools like Cloudflare's Real-time Logs or Vercel's Function Logs. Local development tools are also improving rapidly.

Q: Are edge functions cost-effective? A: For many workloads, yes. You pay only for execution time and requests, with no idle costs. However, complex operations might be more expensive than traditional hosting.

Edge computing is transforming web development by bringing computation closer to users. The key is understanding when and how to use it effectively, combining the right platform with appropriate patterns for your specific use case.