Say a biscuit factory sits in one city. Every shop in the country wants its biscuits. If each shopkeeper had to travel to the factory for every single packet, nobody would buy biscuits. So the factory ships big boxes to a local warehouse in each region, and shops buy from the warehouse down the road.
A CDN is that warehouse system, but for your website's files. CDN stands for content delivery network. It is a group of servers spread around the world that keep copies of your files, so a user in Chennai does not have to fetch an image from a server in Virginia.
The problem it solves
Data travels fast, but not instantly. A round trip from India to the US East coast takes roughly 200 milliseconds on a good day. A normal web page needs dozens of files. Even if the browser asks for several at once, those delays add up, and the page feels slow.
There is a second problem. If your own server has to send every image and every script to every visitor, it burns bandwidth and CPU on work that never changes. Your origin server should be busy running your actual logic, not handing out the same logo a million times.
A CDN fixes both. The user gets files from a server a few milliseconds away, and your server only gets asked when the CDN does not already have the file.
Some words first:
- The origin is your own server (or storage bucket) where the real files live.
- An edge server, also called a point of presence or PoP, is a CDN machine sitting near users. It is the "edge" of the network, close to the people using it.
- A cache hit means the edge already had the file and sent it straight back.
- A cache miss means the edge did not have it and had to ask the origin.
What happens on a request
The first person near that edge pays the long trip. Everyone after them gets the fast answer. That is the whole idea. The rest of this note is details about how to control it.
If you have read about caching in general, this is the same thing: a copy kept close to where it is used. The difference is that a CDN is a cache run by someone else, spread over many cities, sitting in front of you.
Pull CDN and push CDN
There are two ways files get onto the edge servers.
In a pull CDN, you do nothing up front. The first time a user asks an edge for a file, the edge pulls it from your origin and keeps a copy. This is what the sequence diagram above shows. It is the default almost everywhere, and the one I would pick unless you have a reason not to.
In a push CDN, you upload files to the CDN yourself, and it copies them out to the edges. Nothing is fetched from the origin on demand. You are in charge of what is stored and when.
| Pull CDN | Push CDN | |
|---|---|---|
| Who loads the files | The edge, on the first request | You, ahead of time |
| First user near an edge | Pays a slower miss | Gets a fast hit |
| Setup effort | Very small | You need an upload step |
| Storage cost | Only files people actually ask for | Everything you upload, used or not |
| Good for | Websites, many small files, traffic you cannot predict | A few big files you know will be popular, like a game patch or a launch video |
For a normal website with lots of files and unpredictable traffic, pull is simpler. Push makes sense when a file is huge, a million people will want it at the same moment, and you do not want the first wave of users hitting a cold cache and then all landing on your origin together.
What to put on a CDN
The rule is simple. The more people share the same bytes, the more a CDN helps.
Good fits:
- Images, such as product photos and logos.
- JavaScript and CSS files for your web app.
- Fonts.
- Video and audio. This is where CDNs earn their money, since video is huge. Streaming sites break a video into small chunks and the CDN caches the chunks.
- Downloads like installers and PDFs.
- Some API responses, as long as the answer is the same for everybody. A list of countries, the top 10 products on the home page, a public blog post. Even caching it for 30 seconds can take heavy load off your database.
Bad fits:
- Anything personal, like "my orders" or "my account balance". If you cache that by mistake, one user might get another user's data. This is a real and nasty bug, so be careful with it.
- Anything that has to be exactly up to date every second, such as a stock price on a trading screen or the seat map while someone is paying.
- Write requests. A POST that creates an order must reach your origin.
A short test I use: would two different users get the exact same response for this URL? If yes, a CDN can probably help. If no, leave it alone.
Cache headers: how you tell the CDN what to do
The CDN does not guess how long to keep a file. Your origin tells it, using HTTP headers on the response. A header is a small label attached to a response, like a sticker on a parcel.
Three headers matter most.
Cache-Control says how long a copy can be kept and who may keep it. max-age is the number of seconds. public means shared caches like a CDN can store it. private means only the user's own browser may keep it.
ETag is a fingerprint of the file's content. It looks like "a1b2c3". When the cache's copy gets old, it can ask the origin "do you still have version a1b2c3?" If yes, the origin replies with a tiny 304 Not Modified and no body. The cache keeps using its copy and saves the download.
Last-Modified does a similar job using a date. ETag is usually the better one.
Here is a real example. Your origin sends this for a JavaScript file:
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=31536000, immutable
ETag: "9f2c1d"Read it line by line. public says the CDN may store it. max-age=31536000 is one year in seconds. immutable tells the browser this file will never change at this URL, so do not even bother checking again. A year feels risky, but you will see in a moment why it is safe.
Now an API response for the home page's top products:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=10, s-maxage=60
ETag: "top-7731"max-age=10 is for the browser: keep it for 10 seconds. s-maxage=60 is for shared caches like the CDN: keep it for 60 seconds. So you can let the CDN hold on longer than a browser does. With 5,000 requests a second for this page, one 60-second cache means your origin sees about one request per minute per edge instead of 300,000.
And for a personal page:
Cache-Control: private, no-storeno-store means nobody should keep a copy. Use this for account pages and anything with personal data.
One more detail. After max-age runs out, a copy is "stale". A cache with an ETag can ask the origin to check it, which is cheap. Some CDNs can also serve a stale copy while fetching a fresh one in the background (stale-while-revalidate), so the user never waits. It is worth knowing the name even if you never set it.
Invalidation and versioned file names
Here is the catch with caching. You deploy a new app.js with a bug fix, but edges all over the world still hold the old one for a year. Users see the old app. What now?
Option one is invalidation, also called purge. You tell the CDN "forget /app.js everywhere". Most CDNs have an API for it. It works, but it is slow to spread (seconds to minutes), some providers charge for it, and browsers that already hold the file are not affected at all. A purge reaches the edges, not the phones.
Option two is the one most teams really use: change the file name whenever the content changes. Build tools stick a hash of the content into the name.
app.js (old name, avoid for long-cached files)
app.9f2c1d.js (version 1)
app.4be07a.js (version 2, after the bug fix)Your HTML page points at app.4be07a.js now. To the CDN and to every browser, that is a brand new file that nobody has cached, so it is fetched fresh. The old app.9f2c1d.js just sits there and expires on its own. This is why the one year max-age above is safe: a file with a hash in its name never changes. If the content changes, the name changes.
The only file you cannot cache for long is the HTML page that points to those names, because that is where the new names get announced. Give the HTML a short life (a few minutes, or no-cache so it always revalidates) and the hashed files a long one.
So the pattern is: long cache plus versioned names for assets, short cache for the page that references them, and purge only for emergencies, such as you cached the wrong thing or removed a file for legal reasons.
How a request finds the nearest edge
You type cdn.example.com. How does your browser end up talking to the edge in Chennai and not the one in Frankfurt? Two common tricks.
DNS based routing. DNS is the phone book that turns a name into an IP address. The CDN runs its own DNS servers. When yours asks for cdn.example.com, they look at where the question came from and answer with the IP of a nearby edge. Different people asking the same name get different addresses.
Anycast. Many edge servers around the world all announce the same IP address, and the internet's routing sends each packet to whichever one is closest in network terms. One address, many machines.
Most big CDNs use a mix of both. For an interview, you do not need to explain either in detail. "The CDN uses DNS or anycast to send each user to a nearby edge" is enough.
Checking that it really works
Do not trust the setup. Look at the headers on a real response. Most CDNs add a few to tell you what happened. The exact names differ by provider, but they look like this:
curl -sI https://cdn.example.com/img/hero.jpgHTTP/2 200
cache-control: public, max-age=86400
age: 412
x-cache: HITage: 412 says this copy has been sitting in the cache for 412 seconds. x-cache: HIT says the edge answered by itself. Run the same command from a different country (a free online tool can do it) and you will often see a MISS the first time, then a HIT after that.
If you keep getting MISS on a file that should be cached, look at three things. Is there a Set-Cookie header on it? Is there a Cache-Control: no-cache or private that should not be there? Does the URL contain a changing query string, like ?t=1728500000? Any of these is enough to stop caching.
Keeping the origin safe behind the CDN
One more thing people forget. If your origin server still answers anyone on the internet, a bad actor can skip the CDN and hit it directly, and all the protection is gone. Many teams lock the origin so that it only accepts traffic from the CDN's addresses, or requires a secret header the CDN adds. A CDN also soaks up a lot of junk traffic on its own, since an attack on a popular file mostly lands on the edges, not on you.
Cost, and when a CDN is not worth it
CDNs are usually cheap compared to serving everything yourself, because most providers charge by the amount of data sent out, and that rate is often lower than what a cloud provider charges for outbound traffic from your own servers. But the bill is not zero, and it grows with traffic. Video can be very expensive. Purges, extra logs, and custom rules can cost extra on some plans.
A CDN may not be worth the effort when:
- Your users are all in one city, and your server is in that city too. There is not much distance to cut.
- Your traffic is tiny. A site with 200 visitors a day gains little. (That said, many CDNs have a free tier and the setup takes an afternoon, so "not worth it" is often more about complexity than money.)
- Almost everything is personal or changing. If nearly no response can be shared between users, the cache hit rate will be near zero, and you are paying for a hop that does not help.
- You have tight rules about where data may live. Copies of files on servers in many countries can clash with those rules.
The mistake almost everyone makes here is turning on a CDN and never checking the hit rate. Your CDN dashboard shows it. Aim for a high hit rate on static files, 90 percent or more. If it is low, look for a header that is stopping caching (a Set-Cookie or a Cache-Control: no-cache that should not be there) or a URL with a random query string on it, which makes every URL look new.
A small failure story
Say a shop app puts its whole site behind a CDN, including the cart page. The cart page sends Cache-Control: public, max-age=300 by accident. The first user's cart is cached at the edge, and for five minutes, other people in that city see someone else's cart. That is the nightmare case.
The fix is boring: personal responses say private or no-store, and you test it by loading the page as two different users. Do this check once. It costs five minutes and saves a bad day.
Interview talking points
If you draw a CDN box, say it in a few sentences.
"Static assets like images, JS and CSS go through a CDN. It pulls from our object storage on the first request and caches at the edge, so most users get the file from nearby. Assets have hashed names and a long max-age, so we never need to purge. The HTML page has a short cache so new deploys show up fast. Personal API calls skip the CDN."
Then add one trade-off to show you thought about it: "The cost is that a stale file can stay out there until it expires, which is why we use versioned names instead of relying on purging."
Where to draw the box: between the user and your load balancer, for static and cacheable traffic. Dynamic requests pass through (or go around) and hit your servers.
Interview questions to check yourself
"What is the difference between a cache hit and a cache miss at an edge?"
A hit means the edge already had the file and answers directly. A miss means it has to fetch from the origin first, which is slower, and then it saves a copy.
"When would you choose a push CDN over a pull CDN?"
When you have a few huge files you know will be popular at a known time, like a game patch, and you do not want the first wave of users all landing on the origin.
"Why is Cache-Control: public, max-age=31536000, immutable safe for app.9f2c1d.js?"
The hash in the name changes whenever the content changes, so that exact URL never holds different bytes. New content gets a new URL.
"What does s-maxage do that max-age does not?"
s-maxagesets the lifetime for shared caches like a CDN only.max-ageapplies to the browser, so you can keep a copy longer in the CDN than in the browser.
"Name two things you should not put behind a CDN with public caching. Personal responses such as account pages or carts, and write requests like POST. Anything that must be exactly fresh each second is also a bad fit."