CDN Explained: How Content Gets Delivered Fast
Learn how Content Delivery Networks work, when to use them, and how they speed up your app globally. Covers edge servers, caching, and CDN providers like Cloudflare.
A user in Tokyo requests your website. Your servers are in Virginia. The data has to travel 10,000 km — even at the speed of light, that's 70ms just for the round trip. Add DNS lookups, TCP handshakes, and TLS negotiation: your page takes 400ms to load.
Another user in New York gets it in 40ms.
CDNs fix this by serving your content from servers close to your users.
What Is a CDN?
A Content Delivery Network is a global network of servers (called edge servers or PoPs — Points of Presence) placed in data centers around the world. When a user requests content, they get it from the nearest edge server instead of your origin server.
Without CDN:
Tokyo user → Virginia origin → 300ms
With CDN:
Tokyo user → Tokyo edge server → 20ms
↑
(cached copy of your content)The edge server stores a cached copy of your content. Your origin server only gets called when the cache is empty or expired.
What CDNs Cache
CDNs work best for content that doesn't change per user:
Static assets: JavaScript bundles, CSS files, images, fonts, videos — the bulk of most web pages.
HTML pages: For static sites (Next.js static export, Hugo, Gatsby), the full HTML can be cached.
API responses: Read-heavy endpoints that return the same data for everyone (product listings, blog posts, prices).
Not ideal for: Personalized content, authenticated endpoints, real-time data.
How Caching Works
When a user requests a file, the edge server checks its cache:
Cache HIT: Edge has the file → return immediately (fast)
Cache MISS: Edge doesn't have it → fetch from origin → cache it → returnYou control how long content is cached via HTTP headers:
# FastAPI example — set cache headers
from fastapi import Response
@app.get("/api/products")
def get_products(response: Response):
response.headers["Cache-Control"] = "public, max-age=300, s-maxage=3600"
# max-age=300: browsers cache for 5 minutes
# s-maxage=3600: CDN caches for 1 hour
return {"products": [...]}
@app.get("/api/user/profile")
def get_profile(response: Response):
response.headers["Cache-Control"] = "private, no-store"
# private: don't cache in CDN (user-specific data)
return {"user": {...}}Cache-Control: public, s-maxage=3600 — CDN caches this for 1 hour.
Cache-Control: private, no-store — CDN passes through to origin every time.
Cache Invalidation
Content changes. How do you tell the CDN to stop serving the old version?
Versioned URLs: Add a hash or version to asset filenames. When content changes, the URL changes — no cache problem.
<!-- Old -->
<script src="/app.js"></script>
<!-- With versioning — CDN caches indefinitely, URL changes on deploy -->
<script src="/app.abc123.js"></script>This is what Webpack, Vite, and Next.js do automatically with content hashing.
API purge: CDNs provide APIs to manually invalidate cached content.
# Cloudflare: purge specific URLs
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer TOKEN" \
-d '{"files": ["https://example.com/api/products"]}'
# Purge everything
curl -X POST ".../purge_cache" \
-d '{"purge_everything": true}'Short TTLs: For content that changes frequently, use short cache times (60s) instead of long ones. Slightly stale but never old.
What CDNs Do Beyond Caching
Modern CDNs like Cloudflare do more than serve cached files:
DDoS protection: Absorbs attack traffic at the edge before it reaches your origin. Cloudflare handles terabits of attack traffic.
Rate limiting: Block abusive clients at the edge.
WAF (Web Application Firewall): Block SQL injection, XSS, and other attacks before they hit your app.
SSL termination: CDN handles HTTPS. Your origin can serve plain HTTP internally.
Image optimization: Cloudflare Images, Imgix, and Fastly can resize, compress, and convert images on the fly at the edge.
Edge computing: Run code at the edge (Cloudflare Workers, Fastly Compute). Logic runs near the user — useful for auth, A/B testing, redirects.
CDN Providers
Cloudflare: Most popular. Free tier is generous. Strong DDoS, WAF, Workers edge computing. Best choice for most web apps.
AWS CloudFront: Deep AWS integration. Use if you're already on AWS S3 + EC2.
Fastly: Used by GitHub, Spotify. Strong real-time purge (milliseconds vs seconds). Good for dynamic content with short TTLs.
Vercel Edge Network: Built-in for Vercel deployments. Zero configuration.
Azure CDN / Google Cloud CDN: Good if you're on those clouds.
Setting Up with Cloudflare (Common Pattern)
1. Add your domain to Cloudflare
2. Point DNS to Cloudflare (they become your DNS + CDN layer)
3. Traffic flows: User → Cloudflare Edge → Your Origin
4. Configure caching rules:
- /static/* → cache 1 year
- /api/public/* → cache 5 minutes
- /api/user/* → bypass cacheFor a Next.js static site on S3:
User → Cloudflare → S3 bucket (origin)
↓
(caches HTML, JS, CSS at edge globally)S3 only gets called on cache miss. 99% of requests served by Cloudflare's 300+ PoPs worldwide.
When a CDN Doesn't Help
Highly dynamic content: If every response is different (search results, personalized feeds), cache hit rate is low. CDN adds latency without helping much.
Small traffic / single region users: If all your users are in one city and your server is nearby, a CDN may not be worth the cost.
WebSocket / real-time connections: CDNs don't cache streaming connections. These still hit your origin.
Write-heavy workloads: CDNs speed up reads. Writes always go to origin.
Cache Hit Rate: The Key Metric
A good CDN setup has >90% cache hit rate. This means:
- 90%+ requests served from edge, not origin
- Origin gets 10x less load
- Users get consistent low latency globally
If your cache hit rate is low, check:
- Cache-Control headers (are you setting them?)
- URL structure (query strings bust cache — normalize them)
- TTL too short (content expiring too fast)
Key Takeaways
- CDNs serve content from edge servers near users, reducing latency globally
- Works best for static assets, public API responses, and full page HTML
- Cache-Control headers control what gets cached and for how long
- Versioned URLs (content hashing) solve cache invalidation for static assets
- Modern CDNs (Cloudflare) also provide DDoS protection, WAF, and edge compute
- Target >90% cache hit rate — if lower, check your cache headers and TTLs
A CDN is one of the cheapest performance improvements you can make. Set it up before optimizing anything else.
Related reading: Load Balancing Strategies · Rate Limiting Your API · Redis Caching Explained
Enjoyed this article?
Get weekly insights on backend architecture, system design, and Go programming.
Related Posts
Continue reading with these related posts
Redis Caching Explained: Speed Up Your Backend
Learn how Redis caching works, when to use it, and common patterns like cache-aside, write-through, and TTL. With Python and Go examples.
DNS Explained: How the Internet Finds Websites
Learn how DNS translates domain names to IP addresses step by step. Covers DNS resolution, record types, caching, and why it matters for system design.
API Gateway Pattern: The Front Door to Your Services
Learn what an API gateway does, when to use one, and how to set it up. Covers routing, authentication, rate limiting, and tools like Kong, AWS API Gateway, and Traefik.