Open on desktop
Antimetal's interactive diagrams require a larger screen. Open this page on your laptop or desktop to continue.
Content Delivery Network
§1Step 2 — High-Level Design
Design a CDN from scratch. Understand PoP placement, cache hierarchies, and anycast routing.
For static assets (images, CSS, JS), have CDN edges pull directly from object storage, bypassing the origin server entirely.
CDN edges connect directly to object storage for static asset delivery. The origin server only handles dynamic API requests; static files never touch it.
Object storage scales infinitely and is designed for high-throughput random reads. Routing static files through your API server wastes compute and adds latency.
Content must be uploaded to object storage before CDN can serve it. For user-generated content, your upload path must write to object storage directly.
Netflix serves all video content from S3 via CloudFront CDN. GitHub uses Fastly CDN with GitHub Packages as origin storage.
Cloudflare's CDN handles 57M requests/second globally. A single edge PoP can serve 100Gbps+. Object storage scales to exabytes.
For dynamic API responses that can't be CDN-cached (personalized data), add Redis at the origin to serve cache hits without hitting the database.
A Redis cache at the origin serves CDN misses and uncacheable dynamic requests. CDN handles the 90% of traffic that's static; Redis handles dynamic reads.
Without origin-side caching, every CDN miss hits the database. Redis absorbs the miss traffic at sub-millisecond speed.
Two-layer caching (CDN + Redis) adds complexity. Cache invalidation must propagate through both layers — a stale CDN entry may continue serving old data even after Redis is updated.
Instagram uses CloudFront CDN for media with an Elasticache Redis layer at origin for dynamic feed data.
At 90% CDN hit rate, origin sees 10% of traffic. With Redis caching 80% of origin misses, the database sees only 2% of total requests.
At peak load, add a global load balancer in front of multiple origin regions so CDN can failover if one origin region goes down.
A global load balancer routes CDN origin pulls to the nearest healthy origin region using Anycast routing or latency-based DNS.
A single origin region is a single point of failure. At peak traffic, one region may be overwhelmed. Global LB spreads origin load and provides failover.
Cross-region replication adds cost and latency for writes. Read-heavy workloads benefit most; write-heavy ones must handle replication lag.
Cloudflare uses Anycast routing to direct CDN origin pulls to the nearest data center. AWS CloudFront supports multi-region origins with origin groups.
Anycast routes a single IP to 200+ PoPs globally. Failover latency is < 30 seconds for DNS-based, near-instant for Anycast.
§2Step 3 — Deep Dive
CDN edges connect directly to object storage for static asset delivery. The origin server only handles dynamic API requests; static files never touch it.
| Strategy | Freshness | Origin load | Latency | Best for | Cost | Ops burden |
|---|---|---|---|---|---|---|
| No cache (Cache-Control: no-store) | Perfect | High | High | Sensitive, personalized data | Low | Low |
| Short TTL (60s) | Good | Medium | Low | News, scores, near-real-time | Low | Low |
| Long TTL + cache-busting URLs | Perfect | Very low | Very low | Static assets (JS/CSS/images) ✓ | Low | Low |
| Stale-while-revalidate | Excellent | Low | Very low | API responses, semi-static | Low | Low |
| Immutable cache | Perfect | Near zero | Very low | Versioned static files ✓ | Low | Low |
CDN cache strategies — stale-while-revalidate balances freshness and speed.
import express from 'express'
import crypto from 'crypto'
import fs from 'fs'
const app = express()
// Static assets: immutable + content hash in filename
// e.g., /static/app.a1b2c3d4.js → Cache-Control: max-age=31536000, immutable
app.use('/static', express.static('public', {
maxAge: '1y',
immutable: true,
etag: false,
}))
// API responses: stale-while-revalidate
app.get('/api/products', (req, res) => {
res.set('Cache-Control', 'public, max-age=60, stale-while-revalidate=300')
res.json({ products: [] })
})
// Generate content-hashed asset filename at build time
function hashFile(filePath: string): string {
const content = fs.readFileSync(filePath)
const hash = crypto.createHash('md5').update(content).digest('hex').slice(0, 8)
const ext = filePath.split('.').pop()
return `app.${hash}.${ext}`
}| Component | Why Add It | Tradeoff |
|---|---|---|
| Connect CDN Edges to Object Storage Directly | Object storage scales infinitely and is designed for high-throughput random reads. | Content must be uploaded to object storage before CDN can serve it. |
| Redis Cache at the Origin | Without origin-side caching, every CDN miss hits the database. | Two-layer caching (CDN + Redis) adds complexity. |
| Global Load Balancer for CDN Origin Failover | A single origin region is a single point of failure. | Cross-region replication adds cost and latency for writes. |
Design decision tradeoffs
The origin server goes down. CDN edges can still serve cached content — what percentage of requests are served without the origin?
cdn-1 (a regional PoP) goes down. All traffic in that region loses the cache layer and hits the origin directly. How does the CDN failover traffic to cdn-2 or the origin without user-visible errors?
A viral video causes 50x normal traffic to hit the CDN. Cache hit rate drops as CDN nodes become overwhelmed and evict cached content. How do you handle origin shield, pre-warming, and stale-while-revalidate to protect the origin?
§3Step 4 — Wrap Up
| Decision | Choice | Why |
|---|---|---|
| Connect CDN Edges to Object Storage Directly | CDN edges connect directly to object storage for static asset delivery. | Object storage scales infinitely and is designed for high-throughput random reads. |
| Redis Cache at the Origin | A Redis cache at the origin serves CDN misses and uncacheable dynamic requests. | Without origin-side caching, every CDN miss hits the database. |
| Global Load Balancer for CDN Origin Failover | A global load balancer routes CDN origin pulls to the nearest healthy origin region using Anycast routing or latency-based DNS. | A single origin region is a single point of failure. |
Key design decisions