Edge Functions - Edge Computing in Practice

15 min read | 2025.01.21

What are Edge Functions?

Edge Functions are serverless functions that execute code at edge locations (CDN points of presence) closest to users. Compared to traditional serverless (like AWS Lambda), they achieve dramatically lower latency.

flowchart LR
    subgraph Traditional["Traditional Serverless"]
        User1["User<br/>(Tokyo)"] --> Region["Region<br/>(Virginia)"]
        Region --> Response1["Response<br/>200ms"]
    end

    subgraph Edge["Edge Functions"]
        User2["User<br/>(Tokyo)"] --> EdgeLoc["Edge<br/>(Tokyo)"]
        EdgeLoc --> Response2["Response<br/>20ms"]
    end

Major Platforms

1. Cloudflare Workers

One of the most mature edge platforms.

// Cloudflare Worker
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    // Cache check
    const cache = caches.default;
    let response = await cache.match(request);

    if (!response) {
      // Fetch from origin
      response = await fetch(request);

      // Store in cache
      const responseToCache = response.clone();
      responseToCache.headers.set('Cache-Control', 'max-age=3600');
      await cache.put(request, responseToCache);
    }

    return response;
  },
};

2. Vercel Edge Functions

Edge execution environment deeply integrated with Next.js.

// middleware.ts (Next.js)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Geo-based routing
  const country = request.geo?.country || 'US';

  if (country === 'JP') {
    return NextResponse.rewrite(new URL('/jp', request.url));
  }

  // A/B testing
  const bucket = Math.random() < 0.5 ? 'a' : 'b';
  const response = NextResponse.next();
  response.cookies.set('ab-test', bucket);

  return response;
}

export const config = {
  matcher: ['/((?!api|_next/static|favicon.ico).*)'],
};

3. Deno Deploy

Edge platform based on Deno runtime.

// main.ts (Deno Deploy)
Deno.serve(async (req: Request) => {
  const url = new URL(req.url);

  if (url.pathname === '/api/data') {
    // Get data from KV store
    const kv = await Deno.openKv();
    const data = await kv.get(['cache', 'data']);

    if (data.value) {
      return Response.json(data.value);
    }

    // Generate and cache data
    const newData = { timestamp: Date.now(), message: 'Hello from Edge!' };
    await kv.set(['cache', 'data'], newData, { expireIn: 60000 });

    return Response.json(newData);
  }

  return new Response('Not Found', { status: 404 });
});

4. AWS Lambda@Edge / CloudFront Functions

Edge execution environment integrated with AWS CDN.

// CloudFront Function
function handler(event) {
  const request = event.request;
  const headers = request.headers;

  // Device detection
  const userAgent = headers['user-agent']?.value || '';
  const isMobile = /Mobile|Android/i.test(userAgent);

  // Redirect to mobile URL
  if (isMobile && !request.uri.startsWith('/m/')) {
    return {
      statusCode: 302,
      headers: {
        location: { value: `/m${request.uri}` },
      },
    };
  }

  return request;
}

Use Cases

1. Authentication & Authorization

// JWT token verification at the edge
async function verifyToken(request: Request): Promise<Response | null> {
  const authHeader = request.headers.get('Authorization');

  if (!authHeader?.startsWith('Bearer ')) {
    return new Response('Unauthorized', { status: 401 });
  }

  const token = authHeader.slice(7);

  try {
    const payload = await verifyJWT(token, JWT_SECRET);

    // Add user info to headers and forward to origin
    const newRequest = new Request(request, {
      headers: new Headers(request.headers),
    });
    newRequest.headers.set('X-User-ID', payload.sub);

    return null; // Continue
  } catch {
    return new Response('Invalid Token', { status: 401 });
  }
}

2. Personalization

// Content optimization based on geography and language
export default {
  async fetch(request: Request): Promise<Response> {
    const country = request.cf?.country || 'US';
    const language = request.headers.get('Accept-Language')?.split(',')[0] || 'en';

    // Region-specific pricing
    const prices = {
      US: { currency: 'USD', amount: 9.99 },
      JP: { currency: 'JPY', amount: 980 },
      EU: { currency: 'EUR', amount: 8.99 },
    };

    const price = prices[country] || prices['US'];

    // Generate HTML at the edge
    const html = `
      <!DOCTYPE html>
      <html lang="${language}">
      <body>
        <h1>Welcome!</h1>
        <p>Price: ${price.currency} ${price.amount}</p>
      </body>
      </html>
    `;

    return new Response(html, {
      headers: { 'Content-Type': 'text/html' },
    });
  },
};

3. API Gateway

// Rate limiting and routing
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get('CF-Connecting-IP') || 'unknown';

    // Rate limiting (using Cloudflare Durable Objects)
    const rateLimiter = env.RATE_LIMITER.get(env.RATE_LIMITER.idFromName(ip));
    const { allowed } = await rateLimiter.fetch(request).then(r => r.json());

    if (!allowed) {
      return new Response('Too Many Requests', { status: 429 });
    }

    // Path-based routing
    const url = new URL(request.url);
    const routes = {
      '/api/users': 'https://users-service.internal',
      '/api/products': 'https://products-service.internal',
      '/api/orders': 'https://orders-service.internal',
    };

    for (const [path, origin] of Object.entries(routes)) {
      if (url.pathname.startsWith(path)) {
        return fetch(new URL(url.pathname, origin), request);
      }
    }

    return new Response('Not Found', { status: 404 });
  },
};

4. Image Optimization

// Image resizing and format conversion
export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    const imageUrl = url.searchParams.get('url');
    const width = parseInt(url.searchParams.get('w') || '800');
    const format = url.searchParams.get('f') || 'webp';

    if (!imageUrl) {
      return new Response('Missing image URL', { status: 400 });
    }

    // Cloudflare Image Resizing
    return fetch(imageUrl, {
      cf: {
        image: {
          width,
          format,
          quality: 80,
        },
      },
    });
  },
};

Constraints and Optimization

Execution Time Limits

PlatformCPU TimeWall Time
Cloudflare Workers10ms-50ms30s
Vercel Edge25s25s
Deno Deploy50msUnlimited
Lambda@Edge5s30s

Cold Start

// Best practices to minimize cold starts
// 1. Avoid initialization in global scope
// Bad
const heavyConfig = loadHeavyConfig(); // Runs every time

// Good
let cachedConfig: Config | null = null;
function getConfig(): Config {
  if (!cachedConfig) {
    cachedConfig = loadConfig();
  }
  return cachedConfig;
}

Memory Limits

// Save memory with streaming
export default {
  async fetch(request: Request): Promise<Response> {
    const response = await fetch('https://api.example.com/large-data');

    // Stream transformation
    const transformStream = new TransformStream({
      transform(chunk, controller) {
        // Process each chunk
        const processed = processChunk(chunk);
        controller.enqueue(processed);
      },
    });

    return new Response(response.body?.pipeThrough(transformStream), {
      headers: response.headers,
    });
  },
};

Platform Comparison

FeatureCloudflare WorkersVercel EdgeDeno Deploy
RuntimeV8 IsolatesV8 IsolatesDeno
Global PoPs300+100+35+
KV Store◎ Workers KV○ Edge Config◎ Deno KV
Database◎ D1 (SQLite)○ Postgres○ KV
Free Tier100k req/day100k req/mo100k req/day

Summary

Edge Functions are a powerful tool for building globally low-latency applications.

  • Low Latency: Execute closest to users
  • Global Distribution: Automatically deployed worldwide
  • Cost Efficient: Usage-based billing
  • Simple Deployment: Reflect changes instantly with git push

Choose appropriate use cases like authentication, personalization, and API gateways to leverage edge computing effectively.

← Back to list