MinhVo

Minh Vo

rss feed

Slaying code & making it lit fr fr 🔥 tagline

Hey there 👋 I'm an AI Engineer with 7 years of experience building scalable web and mobile applications. Currently at Neurond AI (May 2025 — present), architecting an Enterprise AI Assistant Platform with multi-tenant RAG on pgvector, multi-provider LLM orchestration, and Azure-native infrastructure. Previously spent 5+ years at SNAPTEC (Sep 2019 — Apr 2025), leading SaaS themes, admin dashboards, and e-commerce platforms — earned the Hero of the Year award in 2021. I specialize in TypeScript, React, Next.js, and AI-Native engineering with Claude Code and Cursor.bio

Back to blogs

Edge Computing: The Next Evolution of Cloud

Understand edge computing: CDNs, edge functions, edge databases, and changing architecture.

Edge ComputingCloudArchitecturePerformance

By MinhVo

Introduction

Cloud computing transformed the software industry by abstracting away infrastructure management. Developers no longer needed to buy servers, configure networking, or manage hardware. But the cloud introduced its own problem: latency. When a user in Sydney makes a request to a server in Virginia, the data travels 16,000 kilometers round-trip, adding 150-200ms of unavoidable latency. For many applications, this is unacceptable.

Edge computing solves this by distributing computation across hundreds of locations worldwide, placing it as close to users as physically possible. The CDN that once only cached static files now runs full application logic. The edge node that served images now queries databases. This evolution from passive caching to active computation at the edge represents the next major shift in cloud architecture.

This guide explains the evolution from centralized cloud to distributed edge computing, the technologies enabling this shift, and the architectural patterns that make it practical. We will cover CDN evolution, edge functions, edge databases, and how to design applications that leverage the edge for real performance improvements.

Cloud computing data center with distributed network

Understanding Edge Computing: The Evolution

From CDN to Edge Platform

The CDN (Content Delivery Network) was the first step toward edge computing. Akamai, founded in 1998, deployed servers in data centers worldwide to cache static content closer to users. When a user in Tokyo requested an image from a US-based website, the CDN served it from a Tokyo data center in 5ms instead of 200ms.

Modern CDNs have evolved into full edge computing platforms. Cloudflare Workers, launched in 2017, allowed developers to run JavaScript at 300+ edge locations. Vercel Edge Functions, Deno Deploy, and AWS Lambda@Edge followed. These platforms don't just cache content — they execute application logic at the edge.

The evolution followed a clear path: static caching (2000s) → dynamic content acceleration (2010s) → edge compute (2020s) → edge data (2020s). Each step moved more of the application stack closer to the user.

The Physics of Latency

Latency is ultimately constrained by the speed of light. Data traveling through fiber optic cables moves at approximately 200,000 km/s. A round-trip from New York to London is about 120ms — a physical limit that no software optimization can overcome.

Edge computing addresses this by reducing the physical distance data must travel. If computation happens 50km from the user instead of 10,000km, latency drops from 100ms to under 1ms. This is not an optimization — it is a different physical reality.

DistanceRound-trip LatencyUser Experience
50km (edge)<1msInstant
500km (regional)~5msVery fast
5,000km (continent)~50msAcceptable
15,000km (cross-ocean)~150msSluggish

Edge Computing Models

Client Edge: Computation on the user's device — browser, mobile app, desktop application. PWA caching, service workers, and client-side ML inference are forms of client edge computing.

Network Edge: Computation at telecom infrastructure — cell towers, ISP nodes, and CDN edge locations. This is where Cloudflare Workers and Vercel Edge Functions execute.

Cloud Edge: Computation at regional cloud data centers — not the primary region but smaller, distributed facilities. AWS Local Zones and Azure Edge Zones represent this model.

On-Premise Edge: Computation at the physical location where data is generated — factories, retail stores, vehicles. This is the traditional "IoT edge" model.

Distributed computing architecture diagram

Architecture and Design Patterns

The Edge-Native Architecture

An edge-native architecture is designed from the ground up to run at the edge. This differs from simply deploying a cloud application to edge functions — the entire application model must account for edge constraints: limited execution time, no persistent state, and distributed data.

// Edge-native request handling
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const cache = caches.default;
    const cacheKey = new Request(request.url, request);
 
    // L1: Edge cache (fastest, <1ms)
    let response = await cache.match(cacheKey);
    if (response) {
      response.headers.set('X-Cache', 'HIT');
      return response;
    }
 
    // L2: Edge KV (fast, <5ms)
    const kvKey = new URL(request.url).pathname;
    const kvData = await env.KV.get(kvKey, 'json');
    if (kvData) {
      response = Response.json(kvData);
      response.headers.set('X-Cache', 'KV-HIT');
      await cache.put(cacheKey, response.clone());
      return response;
    }
 
    // L3: Edge database (moderate, <20ms)
    const dbResult = await env.DB.prepare(
      'SELECT * FROM pages WHERE path = ?'
    ).bind(kvKey).first();
 
    if (dbResult) {
      response = Response.json(dbResult);
      response.headers.set('X-Cache', 'DB-HIT');
      // Populate KV for next request
      await env.KV.put(kvKey, JSON.stringify(dbResult), { expirationTtl: 300 });
      await cache.put(cacheKey, response.clone());
      return response;
    }
 
    // L4: Origin (slowest, 50-200ms)
    response = await fetch(request);
    response.headers.set('X-Cache', 'MISS');
    return response;
  },
};

The Compute-Data Affinity Pattern

In edge computing, compute and data should be co-located. If your edge function queries a database in Virginia, you've added a round-trip that negates the edge advantage. The compute-data affinity pattern ensures that data is replicated to the same locations where computation happens.

// Turso: Database replicated to edge locations
import { createClient } from '@libsql/client';
 
// Client automatically routes to nearest replica
const db = createClient({
  url: 'libsql://your-db.turso.io',
  authToken: env.TURSO_AUTH_TOKEN,
});
 
export default {
  async fetch(request: Request): Promise<Response> {
    // This query runs against the nearest edge replica
    // Latency: <5ms regardless of user location
    const result = await db.execute(
      'SELECT * FROM products WHERE category = ?',
      ['electronics']
    );
 
    return Response.json(result.rows);
  },
};

The Geo-Routing Pattern

Route requests to the nearest edge or region based on the user's geographic location:

// Geo-based routing at the edge
export default {
  async fetch(request: Request): Promise<Response> {
    const country = request.cf?.country || 'US';
    const continent = request.cf?.continent || 'NA';
 
    // Map regions to origin servers
    const origins: Record<string, string> = {
      AS: 'https://api-as.example.com',
      EU: 'https://api-eu.example.com',
      NA: 'https://api-na.example.com',
      SA: 'https://api-na.example.com', // Fall back to NA
      AF: 'https://api-eu.example.com', // Fall back to EU
      OC: 'https://api-as.example.com', // Fall back to AS
    };
 
    const origin = origins[continent] || origins.NA;
 
    // Forward to nearest origin
    const url = new URL(request.url);
    const response = await fetch(`${origin}${url.pathname}`, {
      method: request.method,
      headers: request.headers,
    });
 
    // Add routing headers for debugging
    const newResponse = new Response(response.body, response);
    newResponse.headers.set('X-Routed-To', origin);
    newResponse.headers.set('X-User-Country', country);
 
    return newResponse;
  },
};

The Stale-While-Revalidate Pattern

Serve cached content immediately while refreshing it in the background:

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const cache = caches.default;
    const cacheKey = new Request(request.url, request);
    const cached = await cache.match(cacheKey);
 
    if (cached) {
      const age = parseInt(cached.headers.get('Age') || '0');
      const maxAge = parseInt(
        cached.headers.get('Cache-Control')?.match(/max-age=(\d+)/)?.[1] || '60'
      );
 
      if (age < maxAge) {
        // Fresh — serve immediately
        return cached;
      }
 
      // Stale — serve immediately but revalidate in background
      const responsePromise = fetchFromOrigin(request);
      c.waitUntil(
        responsePromise.then(async (fresh) => {
          fresh.headers.set('Cache-Control', `max-age=${maxAge}`);
          await cache.put(cacheKey, fresh);
        })
      );
 
      return cached; // Serve stale content
    }
 
    // No cache — fetch from origin
    const response = await fetchFromOrigin(request);
    response.headers.set('Cache-Control', 'max-age=60');
    await cache.put(cacheKey, response.clone());
    return response;
  },
};

Step-by-Step Implementation

Let's build a complete edge-native blog platform with edge rendering, edge database, and edge caching.

Setting Up the Edge Stack

# Create Cloudflare Workers project
npm create cloudflare@latest edge-blog -- --type=hello-world
cd edge-blog
 
# Install dependencies
npm install hono @libsql/client

Defining the Edge Database Schema

-- Turso/LibSQL schema
CREATE TABLE posts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  slug TEXT UNIQUE NOT NULL,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  author TEXT NOT NULL,
  published_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  views INTEGER DEFAULT 0
);
 
CREATE INDEX idx_posts_slug ON posts(slug);
CREATE INDEX idx_posts_published ON posts(published_at DESC);

Building the Edge Application

import { Hono } from 'hono';
import { createClient } from '@libsql/client';
 
type Bindings = {
  TURSO_URL: string;
  TURSO_AUTH_TOKEN: string;
  KV: KVNamespace;
};
 
const app = new Hono<{ Bindings: Bindings }>();
 
// Middleware: Edge timing
app.use('*', async (c, next) => {
  const start = Date.now();
  await next();
  c.header('X-Edge-Time', `${Date.now() - start}ms`);
  c.header('X-Edge-Region', c.req.header('cf-colo') || 'unknown');
});
 
// Homepage: Latest posts from edge database
app.get('/', async (c) => {
  const db = createClient({
    url: c.env.TURSO_URL,
    authToken: c.env.TURSO_AUTH_TOKEN,
  });
 
  const posts = await db.execute(
    'SELECT id, slug, title, author, published_at FROM posts ORDER BY published_at DESC LIMIT 20'
  );
 
  return c.html(`
    <!DOCTYPE html>
    <html>
      <head><title>Edge Blog</title></head>
      <body>
        <h1>Latest Posts</h1>
        ${posts.rows
          .map(
            (p) => `
          <article>
            <h2><a href="/posts/${p.slug}">${p.title}</a></h2>
            <span>By ${p.author} on ${p.published_at}</span>
          </article>
        `
          )
          .join('')}
      </body>
    </html>
  `);
});
 
// Post page: Single post with view counter
app.get('/posts/:slug', async (c) => {
  const slug = c.req.param('slug');
  const db = createClient({
    url: c.env.TURSO_URL,
    authToken: c.env.TURSO_AUTH_TOKEN,
  });
 
  // Increment view count (write to edge DB)
  await db.execute('UPDATE posts SET views = views + 1 WHERE slug = ?', [slug]);
 
  // Read post (from nearest edge replica)
  const post = await db.execute('SELECT * FROM posts WHERE slug = ?', [slug]);
 
  if (post.rows.length === 0) {
    return c.html('<h1>Post not found</h1>', 404);
  }
 
  const p = post.rows[0];
  return c.html(`
    <!DOCTYPE html>
    <html>
      <head><title>${p.title}</title></head>
      <body>
        <h1>${p.title}</h1>
        <p>By ${p.author} · ${p.views} views</p>
        <div>${p.content}</div>
      </body>
    </html>
  `);
});
 
export default app;

Edge database architecture showing data replication

Real-World Use Cases and Case Studies

Use Case 1: Global SaaS Platform

A project management SaaS serves customers across 40 countries. Before edge computing, all requests routed to US-East, giving European and Asian users 150-300ms response times. After moving to edge computing with Cloudflare Workers and Turso, response times dropped to 10-30ms globally. Customer satisfaction scores in Asia-Pacific increased by 23%.

Use Case 2: E-Commerce Flash Sales

An e-commerce platform runs flash sales that generate 100x normal traffic spikes. Edge functions handle authentication, rate limiting, and inventory checks at the edge, reducing origin load by 95%. The edge KV store holds real-time inventory counts, and only purchase transactions reach the origin server. The platform now handles 50,000 concurrent users without degradation.

Use Case 3: Multi-Tenant API Platform

A B2B API platform serves 10,000 tenants with different rate limits, authentication methods, and response formats. Edge functions handle tenant identification, rate limiting, and request transformation at the edge. Each tenant's configuration is cached in edge KV, updated via webhooks. This architecture reduced API latency from 120ms to 8ms while maintaining per-tenant customization.

Best Practices for Production

  1. Design for eventual consistency: Edge databases are replicated asynchronously in most configurations. Design your application to tolerate brief periods of inconsistency. Use version vectors or timestamps for conflict resolution.

  2. Minimize origin hits: Every request that reaches the origin is a missed edge opportunity. Track your edge hit rate — aim for 95%+ of requests handled at the edge. Use progressive caching strategies.

  3. Use edge-compatible frameworks: Hono, itty-router, and Elysia are designed for edge constraints. Express, Fastify, and Koa rely on Node.js APIs that don't work at the edge. Choose frameworks that use Web Standard APIs.

  4. Implement circuit breakers: If an edge database or origin server becomes unavailable, serve stale content from cache rather than returning errors. Users prefer slightly outdated content over error pages.

  5. Optimize for edge cold starts: Keep edge function bundles under 500KB. Use tree-shaking to remove unused code. Avoid heavy dependencies like lodash — use native JavaScript instead. Every KB adds to cold start time.

  6. Deploy to multiple edge platforms: Avoid vendor lock-in by using runtime-agnostic frameworks like Hono that run on Cloudflare, Vercel, Deno, and Bun. Test on multiple platforms to catch compatibility issues.

  7. Monitor per-edge-location performance: Aggregate metrics hide edge-specific problems. A misbehaving edge node in São Paulo won't show up in global averages. Monitor P99 latency per location.

  8. Use edge for security: Implement WAF rules, bot detection, and DDoS protection at the edge. These concerns benefit most from edge execution because they need to run before requests reach your application.

Common Pitfalls and Solutions

PitfallImpactSolution
Assuming Node.js APIs availableRuntime errors at edgeUse Web Standard APIs: Fetch, Web Crypto, Streams
Querying centralized DB from edgeNegligible latency improvementUse edge databases (Turso, Neon) or cache in KV
Large function bundlesSlow cold starts, deployment failuresTree-shake, dynamic imports, keep under 500KB
Ignoring edge consistency modelStale data, race conditionsDesign for eventual consistency, use version vectors
No edge failure fallbackComplete outageCache stale content, implement origin fallback
Vendor lock-inMigration difficultyUse runtime-agnostic frameworks (Hono, Web Standard APIs)

Performance Optimization

Edge computing delivers measurable performance improvements across every metric:

// Edge performance monitoring middleware
export function edgeMetrics() {
  return async (c: Context, next: () => Promise<void>) => {
    const start = performance.now();
    const startCPU = Date.now();
 
    await next();
 
    const duration = performance.now() - start;
 
    // Log metrics for analysis
    const metrics = {
      path: c.req.path,
      method: c.req.method,
      status: c.res.status,
      duration: Math.round(duration * 100) / 100,
      edgeLocation: c.req.header('cf-colo'),
      country: c.req.header('cf-ipcountry'),
      cacheStatus: c.res.headers.get('X-Cache'),
      timestamp: new Date().toISOString(),
    };
 
    // Send to analytics (non-blocking)
    c.executionCtx.waitUntil(
      fetch('https://analytics.example.com/edge-metrics', {
        method: 'POST',
        body: JSON.stringify(metrics),
      })
    );
  };
}

Comparison with Alternatives

FeatureEdge ComputingCloud ComputingOn-Premise
Global Latency<50ms50-300msRegional only
Cold Start5-20ms100-500msNone
ScalingAutomaticAutomaticManual
Data LocalityPer-regionSingle regionSingle location
Cost ModelPer-requestPer-request/instanceFixed
Node.js SupportLimitedFullFull
Best ForLatency-sensitive appsComplex computationCompliance requirements

Advanced Patterns

Edge Compute with Streaming Responses

// Stream data from edge to client
export default {
  async fetch(request: Request): Promise<Response> {
    const { readable, writable } = new TransformStream();
    const writer = writable.getWriter();
 
    // Stream data in chunks from edge
    (async () => {
      const encoder = new TextEncoder();
 
      for (let i = 0; i < 100; i++) {
        await writer.write(
          encoder.encode(`data: ${JSON.stringify({ count: i })}\n\n`)
        );
        await new Promise((r) => setTimeout(r, 100));
      }
 
      await writer.close();
    })();
 
    return new Response(readable, {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
      },
    });
  },
};

Multi-Layer Edge Caching

// Multi-layer caching: browser → edge cache → edge KV → origin
async function multiLayerFetch(
  request: Request,
  env: Env
): Promise<Response> {
  const url = new URL(request.url);
  const key = url.pathname;
 
  // L1: Browser cache (checked by client, controlled via headers)
  // L2: Edge cache (CDN layer)
  const cache = caches.default;
  const cached = await cache.match(request);
  if (cached) return cached;
 
  // L3: Edge KV (persistent key-value store)
  const kvData = await env.KV.get(key, { type: 'json' });
  if (kvData) {
    const response = Response.json(kvData);
    await cache.put(request, response.clone());
    return response;
  }
 
  // L4: Origin server
  const response = await fetch(request);
  const data = await response.json();
 
  // Populate all layers
  await env.KV.put(key, JSON.stringify(data), { expirationTtl: 300 });
  const cacheableResponse = Response.json(data, {
    headers: { 'Cache-Control': 's-maxage=60' },
  });
  await cache.put(request, cacheableResponse.clone());
 
  return cacheableResponse;
}

Testing Strategies

import { unstable_dev } from 'wrangler';
 
describe('Edge Blog Application', () => {
  let worker: any;
 
  beforeAll(async () => {
    worker = await unstable_dev('src/index.ts', {
      experimental: { disableExperimentalWarning: true },
    });
  });
 
  afterAll(async () => {
    await worker.stop();
  });
 
  test('homepage renders within 50ms', async () => {
    const start = performance.now();
    const resp = await worker.fetch('/');
    const duration = performance.now() - start;
 
    expect(resp.status).toBe(200);
    expect(duration).toBeLessThan(50);
  });
 
  test('includes edge timing headers', async () => {
    const resp = await worker.fetch('/');
    expect(resp.headers.get('X-Edge-Time')).toBeDefined();
    expect(resp.headers.get('X-Edge-Region')).toBeDefined();
  });
 
  test('blog post returns correct content', async () => {
    const resp = await worker.fetch('/posts/test-post');
    const html = await resp.text();
    expect(html).toContain('test-post');
  });
});

Future Outlook

Edge computing is converging with serverless to become the default deployment model. The WebAssembly component model will enable running any language at the edge. Edge AI inference will enable intelligent applications that respond in under 10ms. Edge databases are adding vector search, full-text search, and real-time subscriptions.

The cost economics are shifting too. As edge infrastructure scales, the per-request cost of edge computing is approaching zero. Combined with the latency and user experience benefits, edge computing will become the default architecture for all new web applications within the next 3-5 years.

Conclusion

Edge computing represents the next evolution of cloud computing. By distributing computation across hundreds of locations worldwide, edge computing reduces latency from hundreds of milliseconds to single digits. The technologies are mature: edge functions from Cloudflare, Vercel, and Deno; edge databases from Turso, Neon, and PlanetScale; and edge-compatible frameworks like Hono.

Key takeaways:

  1. Edge computing exists on a spectrum — choose the right level for your needs
  2. Co-locate compute and data for maximum latency benefit
  3. Design for eventual consistency and stateless execution
  4. Use Web Standard APIs for cross-platform compatibility
  5. Implement multi-layer caching: browser → edge cache → edge KV → origin
  6. Monitor per-edge-location performance for regional issues

The edge is not replacing the cloud — it is extending it. Start with edge caching and authentication, then progressively move application logic and data to the edge. Your users will notice the difference immediately.