What Is a CDN and How Does It Work? The Short Answer
A CDN (Content Delivery Network) is a geographically distributed group of servers that stores copies of your website’s files and serves them from the location closest to each visitor. Instead of every request travelling to your single origin server, the CDN answers from an edge location a few milliseconds away.
In one sentence: a CDN works by caching your static assets on hundreds of edge servers worldwide, then intercepting user requests via DNS and serving the cached copy from the nearest edge instead of your origin.
That is the textbook definition you will find on every vendor page. What those pages rarely tell you is when a small site genuinely needs one, what the hidden latency costs are, and how to prove your assets are actually being served from the edge. That is what the rest of this guide covers. Much the same conclusion turns up on stackscale.com.
The Problem a CDN Solves: Distance Is Latency
Data on the internet travels at roughly two thirds the speed of light through fibre, and it never travels in a straight line. Add routing hops, congestion, and peering detours, and you get real numbers that look like this:
| Route | Typical round-trip time (RTT) | Cost of a 3-step handshake (DNS + TCP + TLS) |
|---|---|---|
| Same city | 5 to 15 ms | ~40 ms |
| Paris to Frankfurt | 15 to 25 ms | ~75 ms |
| Paris to Virginia (US East) | 80 to 100 ms | ~300 ms |
| Paris to Sydney | 270 to 320 ms | ~900 ms |
Now multiply that by the number of assets on a typical page (a CSS bundle, two JS chunks, a font, six images) and you understand why a Sydney visitor hitting a Paris-only origin experiences your “fast” site as sluggish. A CDN does not make your server faster. It makes the distance shorter.

How a CDN Works Step by Step: The Full Request Flow
Here is exactly what happens when someone in Sydney loads https://yoursite.com/assets/app.css while your origin lives in a Paris data centre.
Step 1: DNS resolution points the browser to an edge, not your origin
When you put a site behind a CDN, you change your DNS so that your hostname resolves to the CDN instead of your server’s IP. The CDN uses anycast (the same IP announced from many locations) or geo-aware DNS (different answers per region) so the browser connects to the nearest point of presence, or PoP.
Result: the Sydney browser opens a TCP + TLS connection to a Sydney edge server, roughly 5 ms away, instead of Paris at 280 ms. This step alone saves most of the handshake cost before a single byte of content moves.
Step 2: The edge checks its cache
The edge server computes a cache key, usually built from the hostname, the URL path, the query string, and any headers you told it to vary on (for example Accept-Encoding). It then looks that key up in local storage.
- Cache HIT: the file is present and still fresh. The edge returns it immediately. Total time: a few milliseconds. Your origin never hears about this request.
- Cache MISS: the file is not there, or it has expired. The edge must go and fetch it.
Step 3: On a miss, the edge fetches from origin (or from a mid-tier cache)
The edge opens a connection back to your origin server. Good CDNs make this far cheaper than a direct user-to-origin request because of:
- Warm, pooled connections between edge and origin, so no fresh TLS handshake every time.
- Optimised backbone routing instead of the public internet’s shortest-price path.
- Tiered caching / origin shield: the edge asks a regional parent cache first. If a Melbourne user already triggered the fetch, the Sydney edge gets it from the regional cache rather than from Paris.
- Request collapsing: if 500 users request the same uncached file at once, only one request reaches your origin.
Step 4: The edge decides whether to store the response
This is where most misconfigurations live. The CDN reads your response headers to decide cacheability:
Cache-Control: public, max-age=31536000, immutablemeans store it for a year. Perfect for hashed filenames likeapp.4f9c2b.css.Cache-Control: privateorno-storemeans never cache at the edge. Correct for logged-in dashboards, wrong for your logo.Set-Cookieon a static asset will make many CDNs refuse to cache it. Serve assets from a cookie-free path or strip the header.s-maxagelets you tell the CDN one thing and the browser another, for example 5 minutes in the browser and 24 hours at the edge.stale-while-revalidateserves the slightly stale copy instantly while the edge refreshes in the background. This is the single best flag for perceived performance.
Step 5: The response is delivered, and the next user gets a hit
The first Sydney visitor paid the full origin round trip. Every subsequent Sydney visitor within the TTL gets the file straight from the edge. This is why cache hit ratio is the metric that actually matters, not the number of PoPs a vendor advertises.
The flow in numbered form
- User types the URL, browser resolves DNS.
- DNS returns the IP of the nearest CDN edge (anycast or geo-DNS).
- Browser completes TCP + TLS with the edge, typically under 20 ms.
- Edge builds the cache key and checks local storage.
- HIT: content returned, done.
- MISS: edge queries regional shield cache.
- Still a miss: edge fetches from origin over an optimised, pooled connection.
- Origin responds with content plus caching headers.
- Edge stores the copy according to those headers and forwards it to the user.
- Next request for that URL in that region is a hit.

What a CDN Caches (and What It Does Not)
| Content type | Cacheable at edge? | Recommended TTL |
|---|---|---|
| Hashed JS/CSS bundles | Yes, aggressively | 1 year, immutable |
| Images, fonts, icons, video | Yes | 30 days to 1 year |
Unhashed style.css |
Yes, with purge on deploy | 1 hour to 1 day |
| Anonymous HTML pages (blog, docs) | Yes, with care | 1 to 15 min + stale-while-revalidate |
| Public JSON API responses | Sometimes | Seconds to minutes |
| Logged-in pages, carts, admin | No | Bypass / no-store |
| POST, PUT, DELETE requests | No | Always pass through |
Even for uncacheable requests, routing through a CDN is usually still faster than going direct, because the user’s TLS handshake terminates at the nearby edge and the edge-to-origin leg reuses a warm connection. This is often called dynamic acceleration.
Does a Small Site Actually Need a CDN?
Honest answer: not always. Vendor marketing says everyone needs one. Here is a more useful decision framework.
You probably do need a CDN if
- More than roughly 20 percent of your traffic comes from a continent other than the one hosting your origin.
- You serve heavy media: images above 200 KB, video, downloadable files, large font families.
- Your traffic is spiky (launches, newsletters, being featured somewhere) and your origin is a single small VPS.
- You are paying real money for origin egress bandwidth.
- You need WAF, bot filtering, or DDoS absorption in front of the app.
- Your Core Web Vitals show a bad LCP for a specific geography in field data.
You probably do not need a CDN yet if
- Your audience is one country and your server is in that country. Shaving 8 ms off a 20 ms RTT will not change anything a human can perceive.
- Your site is a handful of pages under 500 KB total and already loads in under a second locally.
- Your real bottleneck is server-side: a 900 ms database query, an unoptimised WordPress plugin stack, or a 2 MB uncompressed hero image. A CDN caches slow responses just as happily as fast ones. Fix TTFB and image weight first.
- You are already on a platform (Vercel, Netlify, Cloudflare Pages, Shopify) that includes edge delivery by default. You have a CDN, you just did not configure it.
The latency cost nobody mentions
A CDN is not free of downsides. Be aware of these:
- The cold miss penalty. A cache miss adds an extra hop: user to edge to origin. For a low-traffic site with 300 PoPs, files may expire before a second visitor in that region ever arrives, so you get misses most of the time and each one is slightly slower than going direct. Fix this with tiered caching and longer TTLs.
- An extra DNS lookup if you serve assets from a separate CDN hostname. Preconnect or, better, keep assets on your main domain behind the same CDN.
- Another moving part in the failure chain. When a major CDN has an incident, your site goes down even though your origin is healthy.
- Purge complexity. Stale content bugs are real. Content-hash your filenames and this mostly disappears.
What it costs versus what it saves
Rough current market shape for a small to medium site:
- Free tiers cover a surprising amount. Cloudflare’s free plan includes unmetered caching and basic DDoS protection. Netlify, Vercel, and Cloudflare Pages bundle edge delivery into their free hobby tiers.
- Cheap pay-as-you-go providers like Bunny.net sit in the fractions-of-a-cent-per-GB range, so a site pushing 200 GB a month often lands under a few euros.
- Hyperscaler CDNs (CloudFront, Azure Front Door, Google Cloud CDN) charge per GB plus per 10,000 requests, with regional pricing tiers. Predictable at scale, fiddly at small scale.
- The saving comes from offloaded origin bandwidth and, more importantly, from a smaller server. If a CDN takes 85 percent of your requests, the 20 euro VPS you were going to upgrade can stay a 20 euro VPS.
Rule of thumb: if your monthly origin egress bill is larger than your CDN would be, the CDN pays for itself immediately. If not, buy it for the latency and the security, not the savings.

How to Test Whether Your Assets Are Actually Served From the Edge
This is the part most tutorials skip. Installing a CDN and assuming it works is how sites end up with a 12 percent hit ratio. Verify with response headers. geeksforgeeks.org walks through the specifics.
The one-line curl check
curl -sSI https://yoursite.com/assets/app.4f9c2b.css
Run it twice. The first call may be a MISS while the edge populates. The second should be a HIT. If the second call is still a MISS, something in your headers is blocking caching.
To see the full picture including connection timings:
curl -w "\ndns: %{time_namelookup}s connect: %{time_connect}s tls: %{time_appconnect}s ttfb: %{time_starttransfer}s total: %{time_total}s\n" -o /dev/null -s https://yoursite.com/assets/app.4f9c2b.css
Cache status headers by provider
| Provider | Header to look for | What a good value looks like |
|---|---|---|
| Cloudflare | cf-cache-status, cf-ray |
HIT (also fine: REVALIDATED. Bad: DYNAMIC, BYPASS) |
| AWS CloudFront | x-cache, x-amz-cf-pop |
Hit from cloudfront |
| Fastly | x-cache, x-served-by, x-cache-hits |
HIT, HIT with hit count above 0 |
| Akamai | x-cache |
TCP_HIT or TCP_MEM_HIT |
| Bunny.net | cdn-cache, server: BunnyCDN |
HIT |
| Vercel | x-vercel-cache |
HIT or STALE |
| Netlify | cache-status, x-nf-request-id |
"Netlify Edge"; hit |
| Standardised (RFC 9211) | cache-status |
; hit; ttl=86000 |
Two headers that tell you the truth regardless of vendor
age: seconds the object has been sitting in cache. Ifageis greater than 0, you are being served from cache. If it is always 0 or absent, you are hitting origin every time.via: names the intermediary proxy, for example1.1 varnishor1.1 cloudfront. Its presence confirms a proxy is in the path.
Checking from other continents
A HIT from your own city proves almost nothing. Test globally:
- Run WebPageTest from three or four regions and inspect headers per asset.
- Use a public checker like KeyCDN’s performance test or a looking-glass tool to resolve your hostname from multiple regions and confirm you get different edge IPs or PoP codes.
- In CloudFront, compare
x-amz-cf-popvalues. In Cloudflare, decode the last three letters ofcf-ray(for exampleCDGfor Paris,SYDfor Sydney).
In the browser, in ten seconds
- Open DevTools, Network tab.
- Tick Disable cache so you bypass the browser cache and test the edge, not localStorage.
- Reload, click any static asset, open the Headers panel.
- Look at Response Headers for the cache status header,
age, and the server name. - Add the
cf-cache-statusorx-cachecolumn to the Network table (right click the column header, Response Headers, Manage header columns) so you can scan every request at once.

Five Mistakes That Kill Your Cache Hit Ratio
- Cookies on static assets. A session cookie set on every response makes most CDNs treat the asset as private. Serve assets from a path where cookies are not set.
- Cache-busting query strings that change per user. Appending
?t=1727420708or analytics parameters creates a unique cache key each time. Either ignore query strings for static paths or use content hashes in filenames. - Over-broad
Vary.Vary: User-Agentmultiplies your cache entries by thousands. RestrictVarytoAccept-Encodingand, if you must,Accept. - Short TTLs everywhere. A 60 second TTL on an immutable hashed bundle means you are re-fetching from origin constantly for no benefit.
- Forgetting to purge on deploy. If you do not hash filenames, wire a purge call into your CI pipeline, ideally a targeted purge by URL or cache tag rather than a full flush.
A Sensible Default Configuration
- Hashed assets in
/assets/*:Cache-Control: public, max-age=31536000, immutable - Images and fonts:
Cache-Control: public, max-age=2592000 - Anonymous HTML:
Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=86400 - Authenticated routes:
Cache-Control: private, no-store - Enable Brotli compression, HTTP/2 or HTTP/3, and tiered caching or origin shield.
- Set up a cache hit ratio alert. If it drops below your baseline after a deploy, something in your headers changed.

Key Takeaways
- A CDN works by caching copies of your content on edge servers close to users and using DNS to route requests to the nearest one.
- The request flow is: DNS to edge, cache key lookup, HIT served instantly or MISS fetched from a shield or origin, then stored per your
Cache-Controlheaders. - Static assets are the easy win. Dynamic requests still benefit from a nearby TLS termination point.
- A small single-country site with fast TTFB may not need a CDN at all. Fix server response time and image weight first.
- Always verify with response headers.
cf-cache-status,x-cache,age, andcache-statustell you whether the edge is doing its job.
FAQ
How does a CDN work step by step?
DNS resolves your hostname to the nearest edge server, the browser connects to that edge, the edge builds a cache key from the URL and selected headers, it serves a cached copy if one is fresh, otherwise it fetches from a regional shield cache or your origin, stores the response according to your Cache-Control headers, and returns it to the user. another shop that gets it right treats this as a baseline.
How can I tell if a site is using a CDN?
Run curl -sSI https://thesite.com and look for provider fingerprints in the response headers: cf-ray and server: cloudflare, x-amz-cf-pop, x-served-by for Fastly, x-cache: TCP_HIT for Akamai. You can also run dig or nslookup on the hostname and check whether the returned IP or CNAME belongs to a CDN network.
Can I use a CDN for free?
Yes. Cloudflare’s free plan offers unmetered static caching plus DDoS protection for most sites. Netlify, Vercel, and Cloudflare Pages bundle edge delivery in their free tiers. Public asset CDNs like jsDelivr and unpkg are free for open source libraries. Free tiers usually limit advanced cache rules, analytics retention, and image optimisation.
Who are the largest CDN providers?
Akamai, Cloudflare, Amazon CloudFront, Fastly, and Google Cloud CDN dominate by traffic volume, with Akamai and Cloudflare having the widest PoP footprints. For small projects, Bunny.net and KeyCDN offer strong price-to-performance ratios.
Does a CDN help SEO?
Indirectly but meaningfully. Faster LCP and lower TTFB improve Core Web Vitals, which are a ranking signal, and better availability under traffic spikes prevents crawl errors. A CDN will not fix thin content or bad information architecture. For the wider picture, see Content Delivery Network (CDN) Explained.
What is the difference between a CDN and web hosting?
Hosting runs your application and holds the source of truth (your database, your code). A CDN holds temporary copies of the output and serves them from many locations. A CDN cannot replace your origin, it sits in front of it. Some platforms now blur the line by letting you run code at the edge too.
Will a CDN serve stale content after I deploy?
It can, if you reuse filenames with long TTLs. The reliable fix is content hashing (app.4f9c2b.css) so every deploy produces a new URL, combined with a targeted purge of your HTML entry points in your CI pipeline.