0

CDN — Content Delivery Network: serving static assets from edge nodes

Beginner5 min read·eng-18-007
interviewperformance

Concept

CDN (Content Delivery Network) — a network of geographically distributed servers that cache and serve content from locations closer to the user.

The problem CDNs solve: A server in Frankfurt is slow for a user in Tokyo. Network latency adds 200-300ms for every round trip across the planet. A CDN has "edge nodes" (PoPs — Points of Presence) in Tokyo, so the user's request hits a nearby server instead.

What CDNs cache:

  • Static assets: Images, CSS, JavaScript, fonts. Rarely change — cache for weeks.
  • API responses: Can be cached if the response is the same for all users.
  • HTML: Can cache entire pages if content is not user-specific.

Cache-Control headers: Your server tells the CDN how long to cache content.

  • Cache-Control: public, max-age=31536000 — cache for 1 year (for immutable assets like versioned JS bundles).
  • Cache-Control: no-cache — always check with origin before serving.
  • Cache-Control: private — browser can cache but CDN should not (user-specific responses).

CDN invalidation: When you deploy new code, old CSS/JS files are cached on CDNs. Two solutions:

  1. Cache busting: Include a hash in the filename (app.a3f9b2.css). New deploy = new hash = new URL = CDN fetches fresh. Laravel Mix/Vite does this automatically.
  2. Manual invalidation: Tell the CDN to delete cached files (CDN API call, slower).

Popular CDNs: Cloudflare (also provides security/DDoS protection), AWS CloudFront, Fastly, Bunny CDN.

Full-site CDN: Cloudflare can sit in front of your entire domain — all requests go through Cloudflare's edge, which caches what it can and proxies the rest to your origin.

Code Example

php
<?php
// CACHE-CONTROL headers in Laravel responses
Route::get('/api/products', function () {
    $products = cache()->remember('products', 3600, fn() => Product::all());
    return response()
        ->json($products)
        ->header('Cache-Control', 'public, max-age=3600'); // CDN caches for 1 hour
});

// Different cache for authenticated vs public
Route::get('/api/dashboard', function () {
    return response()
        ->json(auth()->user()->dashboardData())
        ->header('Cache-Control', 'private, no-store'); // CDN must NOT cache this
});

// Static assets — versioned URLs (Vite handles this)
// resources/js/app.js → public/build/assets/app-a3f9b2c1.js
// The hash changes on every build → CDN automatically fetches the new version
// Old version is still valid at old URL (no invalidation needed)