cf.completefrontend
My progress
FUNDAMENTALS · MODULE 2

DNS, CDNs, and the edge

How a name becomes an address, how that address leads to a server a few milliseconds from the user instead of an ocean away, and what code and files a frontend should run and keep there.

The problem: the speed of light is too slow

Picture a small team in Frankfurt that builds a recipe site. Their one server sits in a data centre in Frankfurt. For the team, the site feels instant: the HTML arrives in 40 ms. Then a food blogger in Sydney shares a link, and 50,000 Australians open it in an hour.

For each of them the page takes more than two seconds before anything shows. The server is not slow. The code is not slow. The problem is the 16,500 km between Sydney and Frankfurt, which every request has to cross twice: once there and once back.

Round trip math

Light in optical fibre travels at about 200,000 km per second, roughly two thirds of its speed in a vacuum. That is about 200 km per millisecond. Cables do not follow straight lines, and routers add their own delay, so real paths are often 1.5 to 2 times slower than the straight-line number.

An RTT (round trip time) is the time for a packet to go to the server and for the answer to come back. Sydney to Frankfurt is about 16,500 km one way. The floor is 2 x 16,500 / 200 = 165 ms, and the real RTT is usually around 250 to 300 ms. No amount of money buys a faster speed of light.

One RTT would be fine. The trouble is that loading a page needs many of them, one after the other. Before the first byte of HTML arrives, the browser needs a DNS lookup, a TCP handshake (one RTT), a TLS handshake (one more RTT with TLS 1.3), and the HTTP request itself (one more RTT). That is three to four RTTs before TTFB, the time to the first byte of the response.

The same server, the same code. Only the distance changes, and it multiplies every handshake.
StepUser in Frankfurt (RTT 10 ms)User in Sydney (RTT 280 ms)
DNS lookup (cached at the resolver)about 5 msabout 5 ms
TCP handshake: 1 RTT10 ms280 ms
TLS 1.3 handshake: 1 RTT10 ms280 ms
HTTP request and first byte: 1 RTT plus server time10 ms + 20 ms280 ms + 20 ms
TTFBabout 55 msabout 865 ms

And TTFB is only the start. The HTML names a stylesheet and scripts on the same host (cheap now, the connection is open, but still one RTT each round), then fonts and images. A page with three rounds of requests pays the Sydney RTT at least three more times. Two seconds is easy to reach.

A bar chart of time to first byte, drawn to scale. A user in Frankfurt with the server in Frankfurt: about 55 ms. A user in Sydney with the server in Frankfurt and no CDN: about 865 ms. The Sydney user through a Sydney PoP on a cache miss: about 325 ms. The Sydney user through a Sydney PoP on a cache hit: about 35 ms.TTFB, to scaleFrankfurt user, server in Frankfurt (RTT 10 ms)55 msSydney user, server in Frankfurt, no CDN (RTT 280 ms)865 msSydney user, Sydney PoP, cache miss325 msSydney user, Sydney PoP, cache hit35 ms
Same server, same code. Distance multiplies every handshake; a nearby PoP takes most of it back, even when nothing is cached.

Three tools that fix it

The web solves the distance problem with three layers that work together. This lesson covers all three, in the order a request meets them.

  1. DNS, the Domain Name System, turns a name like recipes.example into an IP address. It is also the first place where a provider can steer the user to a nearby server.
  2. A CDN, a content delivery network, is a set of servers in hundreds of cities, called PoPs (points of presence). The user's connection ends at the nearest PoP, so handshakes cost a 10 ms RTT, not a 280 ms one, and cached files never cross the ocean at all.
  3. The edge means running your own code on those PoPs: small functions that redirect, rewrite, check a cookie, pick an A/B variant, or even render HTML, a few milliseconds from the user.

Earlier lessons covered parts of this. From URL to pixels walked through the DNS lookup and handshakes once. HTTP caching and CDN caching covered the headers and rules that decide what a cache may keep, and for how long.

This lesson does not repeat those rules. It covers how the network finds a nearby server, what happens there, and what a frontend should put on it.

Check your understanding · Exercise 1

A user in Singapore loads a site whose only server is in Virginia, about 15,500 km away. Which statements are true? Select all that apply.

How DNS turns a name into an address

Computers on the internet find each other by IP address, like 203.0.113.7 (IPv4) or 2001:db8::7 (IPv6). People use names. DNS is the global, distributed phone book that maps one to the other. No single server holds the whole book: it is split into a tree, and each part is run by whoever owns that part of the name.

The four servers in a lookup

Read a name from right to left and you walk down the tree. www.recipes.example sits under recipes.example, which sits under example, which sits under the root (an invisible dot at the end). Four kinds of servers take part in a lookup.

  • Stub resolver: a small library in the operating system. It does not walk the tree. It asks one configured resolver and waits. The browser talks to it, or, with DNS over HTTPS turned on, skips it and asks a resolver directly.
  • Recursive resolver: the server that does the real work, run by the internet provider, the company network, or a public service like 1.1.1.1 or 8.8.8.8. It walks the tree on the user's behalf and caches every answer it gets, for every user it serves.
  • Root and TLD servers: the root servers know only who runs each top-level domain (TLD) such as .com, .org, or .io. The TLD servers know only which name servers are in charge of each domain under them. There are 13 root server names, a to m, but each is served from many places: well over a thousand sites worldwide.
  • Authoritative server: the server that holds the real records for your domain. It is run by your DNS provider (Route 53, Cloudflare DNS, NS1, your registrar). Its answers are the truth; everyone else only caches them.
A sequence diagram of a cold DNS lookup with five columns: browser, recursive resolver, root server, the .example TLD server, and the authoritative name server. The browser asks the resolver for www.recipes.example. The resolver asks the root, which refers it to the .example servers. It asks the TLD server, which refers it to ns1.dnsprovider.net. It asks the authoritative server, which answers with a CNAME to the CDN and then an address. The resolver returns 198.51.100.20 to the browser and caches every answer for its TTL.BrowserResolverRoot.exampleAuth NSwww.recipes?.example NS?ask TLDrecipes NS?ask ns1www A?CNAME + A198.51.100.20
Only a cold lookup walks the whole tree. The root and TLD referrals are cached for up to two days, so most lookups are one trip from the browser to the resolver and, at most, one from the resolver to the authoritative server.

A cold lookup, step by step

Say nobody has looked up www.recipes.example for a while, so no cache has it. Here is the walk, with typical times for a resolver in the same city as the user.

  1. The browser checks its own small cache, then asks the stub resolver, which checks the OS cache. Both miss. The stub sends one UDP packet to the recursive resolver (about 5 to 20 ms on a home connection).
  2. The resolver asks a root server: who runs .example? The root answers with a referral, a list of TLD name servers. The resolver almost always has this cached already, because the TTL on TLD referrals is two days.
  3. The resolver asks a .example TLD server: who runs recipes.example? Another referral, this time to ns1.dnsprovider.net and the other name servers of your DNS provider. Often cached too.
  4. The resolver asks the authoritative server for www.recipes.example. The answer is a CNAME pointing at recipes.cdn-provider.net, a name the CDN owns.
  5. The resolver now has to resolve that new name, which may need its own walk to the CDN's authoritative servers. They answer with an A and an AAAA record for a nearby PoP.
  6. The resolver caches every answer for its TTL and sends the final addresses back to the stub, which gives them to the browser.

A fully cold lookup like this can take 100 to 300 ms. In practice it is rare for a popular site: the resolver serves thousands of users, so the answer is usually in its cache and the lookup costs one short trip to the resolver.

The records a frontend meets

From URL to pixels covered the HTTPS record in more detail.
RecordWhat it holdsExampleWhere you meet it
A / AAAAAn IPv4 / IPv6 address203.0.113.7The final answer the browser connects to.
CNAMEAnother name to look up insteadwww to recipes.cdn-provider.netPointing your host name at a CDN or a hosting platform.
NSThe name servers in charge of a domainns1.dnsprovider.netMoving your domain to a new DNS provider.
HTTPSConnection hints: protocols, ports, address hintsalpn="h2,h3"Letting the browser use HTTP/3 on the first visit.
TXTFree textv=spf1 ..., verification tokensProving you own the domain to a CDN or certificate authority.

One trap: a CNAME is not allowed at the apex, the bare domain recipes.example, because the apex must also hold NS and other records, and a CNAME cannot sit next to anything else. DNS providers work around it with a non-standard feature, called ALIAS, ANAME, or CNAME flattening, which resolves the target on their side and returns plain A and AAAA records. If a CDN setup guide asks for a CNAME on the apex, this is the feature you need.

TTLs: how long an answer may be cached

Every record carries a TTL, time to live, in seconds. A resolver that got an answer with TTL 300 may hand it out for up to five minutes without asking again. TTLs are the whole reason DNS is fast and cheap, and the whole reason DNS changes are slow.

text
$ dig www.recipes.example

;; ANSWER SECTION:
www.recipes.example.        3600  IN  CNAME  recipes.cdn-provider.net.
recipes.cdn-provider.net.     60  IN  A      198.51.100.20
recipes.cdn-provider.net.     60  IN  AAAA   2001:db8:20::1

;; Query time: 14 msec
A typical CDN setup: a long TTL on your CNAME, which rarely changes, and a short TTL on the CDN's addresses, so the CDN can move traffic quickly.
  • Long TTLs (an hour to a day) mean fewer lookups and less load on your DNS provider, but any change takes up to that long to reach everyone.
  • Short TTLs (30 to 300 seconds) let you move traffic fast, at the cost of more lookups. CDNs use short TTLs on their own records for exactly this reason.
  • TTLs count down in every cache. A resolver that cached the answer 50 minutes ago hands it out with 10 minutes left, and the browser and OS cache it for at most that long.

Negative caching: remembering that a name does not exist

Resolvers also cache failures. If a name does not exist, the authoritative server says NXDOMAIN, and the resolver remembers that answer. How long is set by the SOA (start of authority) record of the zone: the smaller of the SOA record's own TTL and its minimum field, per RFC 2308. Common values run from a few minutes to an hour, and many resolvers also cap it at a few hours.

This bites during launches. Someone tests beta.recipes.example before the record exists, the resolver caches NXDOMAIN for an hour, and when the record is created five minutes later, everyone behind that resolver still gets an error. Create records before anyone looks them up, and check the SOA negative TTL first.

Cached
Name exists at first lookup
A DNS lookup of www.recipes.example. stub to resolver: 12 ms. resolver to root: 10 ms. resolver to TLD: 30 ms. resolver to auth NS: 35 ms. resolver to CDN NS: 20 ms. Total: 107 ms. Answer: 198.51.100.20 (A record, TTL 60, behind a CNAME with TTL 3600).steps, one after another, to scalestub to resolver12 msresolver to root10 msresolver to TLD30 msresolver to auth NS35 msresolver to CDN NS20 mstotal: 107 ms198.51.100.20 (A record, TTL 60, behind a CNAME with TTL 3600)
Each warm cache cuts steps from the walk. Records with different TTLs expire at different times, and a cached NXDOMAIN keeps failing even after the record is created.

Check your understanding · Exercise 2

Your www record has TTL 3600. At 10:00 you change it to a new address. Which statements are true? Select all that apply.

Finding the nearest PoP: DNS steering and anycast

A CDN has PoPs in hundreds of cities. A user in Mumbai should land in the Mumbai PoP, not in London. Something has to make that choice for every new connection, with no help from the user. CDNs use two methods, often together: answer differently in DNS, or give every PoP the same address and let the internet's routers pick.

DNS-based steering

With DNS steering (often called GeoDNS), each PoP has its own IP addresses. The CDN runs the authoritative servers for its own names, like recipes.cdn-provider.net. When a resolver asks, the CDN looks at where the question comes from and answers with the addresses of a PoP near it. Mumbai resolvers get Mumbai addresses; Paris resolvers get Paris addresses.

The catch: the CDN sees the address of the resolver, not the user. That is fine when the resolver is the user's internet provider in the same city. It goes wrong when the user picks a public resolver whose nearest site is in another country, or a company routes all DNS through its head office. The CDN then picks a PoP near the resolver, which may be far from the user.

The fix is EDNS Client Subnet (ECS, RFC 7871): the resolver passes along a shortened form of the user's address, such as the first 24 bits of an IPv4 address, so the CDN can pick by the user's network. Some resolvers send it, some do not, on purpose, because it leaks a little about the user to every authoritative server. Steering works best with it, and still works without it, just less precisely.

DNS steering has one big strength: the CDN can change its answer at any moment, for any reason. It can send users away from a PoP that is overloaded, or toward a cheaper one, or measure real latency from each network and pick the fastest PoP, not just the closest on the map. The price is that each change only takes effect when cached answers expire, which is why CDN records often have TTLs of 20 to 60 seconds.

Anycast

With anycast, every PoP announces the same block of IP addresses to the internet. The routers that join networks together share routes with BGP, the Border Gateway Protocol, and each router forwards a packet along the shortest route it knows to that address. Since many PoPs claim it, each user's packets end up at whichever PoP is closest in network terms. One address, hundreds of places.

A graph of anycast routing. Users in Lisbon, Mumbai, and Sydney each connect through their provider's router. Three PoPs, in Lisbon, Mumbai, and Sydney, all announce the same address, 198.51.100.1. Each router sends packets along its shortest known route: Lisbon to the Lisbon PoP in 1 hop, Mumbai to the Mumbai PoP in 1 hop, Sydney to the Sydney PoP in 1 hop. The Mumbai router also knows a 4-hop route to Lisbon, which it does not use.userstheir routersPoPs, all announce 198.51.100.1LISISP1 hopLisbon PoP198.51.100.1BOMISP1 hopMumbai PoP198.51.100.1SYDISP1 hopSydney PoP198.51.100.14 hopsLIS, BOM, SYD: networks in Lisbon, Mumbai, and Sydney
One address, many places. Each router picks the shortest route it knows, so each user lands in a nearby PoP. If a PoP stops announcing, its users follow the next shortest route within seconds.

Anycast has three strong points. DNS stays simple: every user gets the same answer, so resolver location does not matter. Failover is fast: if a PoP goes down, it stops announcing the route, and usually within seconds routers send its users to the next nearest one, with no TTL to wait out.

And attacks get spread out: a flood of traffic from bots around the world is split across every PoP instead of piling onto one. That is why the DNS root servers and public resolvers like 1.1.1.1 and 8.8.8.8 are anycast too.

The weak points: "closest in network terms" is not always closest on the map. BGP picks routes by the number of networks crossed and by the business deals between them, not by milliseconds. A user can sometimes land in a PoP one country over because their provider's cheapest route goes there. And the CDN has less fine control: it cannot easily move one city's users to a different PoP without changing route announcements, which affects everyone near that PoP.

People sometimes worry that a route change in the middle of a TCP connection will send the next packet to a different PoP that knows nothing of the connection. It can happen, but routes are stable enough that for short web requests it is rare, and large anycast networks have tooling to handle it. Long-lived connections like WebSockets need to reconnect gracefully anyway.

Decision How should a CDN send each user to a nearby PoP?

DNS steering (GeoDNS)

Each PoP has its own addresses.

The CDN's DNS answers with a PoP near the resolver, or near the user's subnet when ECS is sent.

Pros

  • Fine control: shift any network to any PoP at any time.
  • Can steer by measured latency, load, or cost, not just distance.

Cons

  • Guesses from the resolver's location, which can be far from the user.
  • Changes and failover wait for DNS TTLs to expire.

Anycast

Every PoP announces the same addresses through BGP.

Routers carry each user's packets to the nearest announcement.

Pros

  • Same DNS answer for everyone; resolver location does not matter.
  • Failover in seconds by withdrawing a route.
  • Spreads attack traffic over every PoP.

Cons

  • Network-nearest is not always fastest.
  • Coarse control over who lands where.

Both together

Anycast addresses for regions or groups of PoPs, picked by DNS.

Or anycast for DNS itself, with steering in the answers.

Pros

  • Combines fast failover with finer control.

Cons

  • More moving parts; you rely on the CDN to run it well.

What we pick: As a frontend engineer you rarely choose this: it comes with the CDN. What you should know is which kind yours uses, because it changes how failover behaves (seconds with anycast, a TTL with DNS steering) and why a user might see a far PoP (their resolver, or their provider's routing). Cloudflare is built on anycast; Akamai is known for DNS-based mapping; most large CDNs mix both in some form.

Check your understanding · Exercise 3

A user in Lisbon uses a public DNS resolver whose nearest site is in Madrid. Which statements are true? Select all that apply.

What happens inside a PoP

A PoP is not one server. It is a rack or a room of them in a data centre that connects to many local networks: load balancers in front, a fleet of machines that end connections and run code, and caches in memory and on fast SSDs. When the user's packets arrive, three things happen in order: the PoP ends the connection, checks its cache, and if needed, asks the next layer up.

TLS ends at the edge

TLS termination means the PoP, not your server, completes the TLS handshake with the browser. The CDN holds a certificate for your domain (one it issues for you, or one you upload) and decrypts the request in the PoP. This is what makes a CDN help even when nothing is cached: the slow handshakes now cost the short user-to-PoP RTT.

The PoP then sends the request on to your server, the origin, over a second connection. That connection is not new for each user. The PoP keeps a pool of warm, already-encrypted connections to the origin and reuses them for thousands of requests. So the long distance is crossed once per request, not three or four times.

Two panels for a Sydney user and a Frankfurt origin, on a cache miss. Left, no CDN: the TCP handshake, the TLS handshake, and the request each cross the full 280 ms round trip, plus 20 ms of server time, for a TTFB of about 865 ms. Right, with a Sydney PoP: the TCP handshake, TLS handshake, and request each take 10 ms to the PoP, then the PoP forwards the request to the origin over a warm connection in about 290 ms including server time, for a TTFB of about 325 ms.No CDNWith a Sydney PoPUserSydneyOriginFrankfurtUserSydneyPoPSydneyOriginFrankfurtTCP handshake: 280 msTLS handshake: 280 msrequest: 280 + 20 msTCP handshake: 10 msTLS handshake: 10 msrequest to PoP: 10 msPoP to origin: 290 msTTFB about 865 msTTFB about 325 ms
TLS ends at the PoP. The user's handshakes become short, and the long distance is crossed once, over a connection the PoP already holds open.
Even a miss is more than twice as fast, because only one trip crosses the ocean. A hit never leaves Sydney.
StepSydney user, Frankfurt origin, no CDNSydney user, Sydney PoP, cache missSydney PoP, cache hit
TCP handshake280 ms10 ms10 ms
TLS 1.3 handshake280 ms10 ms10 ms
Request to the PoP and back(none)10 ms10 ms
PoP to origin and back, warm connection(none)about 270 ms(none)
Request to the origin and back280 ms(counted above)(none)
Server time20 ms20 msabout 1 ms
TTFB (plus about 5 ms of DNS)about 865 msabout 325 msabout 35 ms

Ending TLS at the edge has two security costs that you should say out loud in a design. First, the CDN sees your traffic in plain text, cookies and all, so it is part of your trust boundary. Second, the hop from the PoP to the origin needs its own TLS with a certificate the CDN checks; a setting like "encrypt to the browser only" leaves that hop open on the public internet.

Also lock the origin down so it only accepts traffic from the CDN: an allowlist of the CDN's address ranges, a secret header the CDN adds, mutual TLS, or a private tunnel. Otherwise an attacker who finds the origin's address skips the CDN entirely, along with its cache, its rate limits, and its firewall.

Cache hit ratio

Once the request is decrypted, the PoP looks it up in its cache. The cache hit ratio is the share of requests answered from cache: hits divided by all requests. It is the single number that says how much a CDN is helping, both for user speed and for origin load.

Small changes in the ratio are big changes in origin load. At 20,000 requests per second, a 95 percent ratio sends 1,000 requests per second to the origin. At 99 percent, it sends 200: five times fewer, from a four point change. Think of it as the miss ratio: going from 5 percent misses to 1 percent divides the origin's work by five.

There are two ways to count it. The request hit ratio counts requests; the byte hit ratio counts bytes. A site can have a 98 percent request ratio because small icons hit, while its big videos miss and most of its bandwidth still comes from the origin. Check both.

Why does the ratio drop? Cache keys that split one file into many copies, Vary on per-user headers, short TTLs, and purging everything on deploy: the CDN caching lesson covers those rules and how to fix them. Here, one cause matters most: the more PoPs, the fewer requests each one sees.

A file asked for 1,000 times an hour, spread over 300 PoPs, reaches most PoPs a few times an hour. Each PoP misses once before it can hit, and may drop rarely used files to make room. Low-traffic and long-tail content suffers most.

Hit ratio
Origin shield
10,000 requests per second reach the CDN. With a 95% hit ratio, 9,500 are answered at the edge and 500 miss. With no shield, 500 requests per second reach the origin. The average response takes about 31 ms.users10,000Edge PoPs9,500/s hits500Shieldoff500Origin500/sorigin load500 req/saverage wait31 msedge hit: 20 ms, shield hit: 200 ms, origin: 240 ms
Every miss goes all the way to the origin. Going from 95% to 99% cuts origin traffic by five times.

Origin shielding and request collapsing

The answer to many PoPs each missing is a second tier. With origin shielding, a PoP that misses asks one chosen cache, the shield, instead of the origin. The shield is a large PoP near your origin. Tiered caching is the wider name for any such second layer, such as regional caches.

Only the shield talks to the origin, so a new file costs the origin about one request, not one per PoP. The shield's own hit ratio is high, because it sees the misses of every PoP below it.

Request collapsing handles the burst case. If 2,000 users ask the same PoP for a just-deployed file in the same second, the PoP sends one request upstream and makes the other 1,999 wait for that answer, instead of sending 2,000. Shields collapse requests across PoPs the same way.

Three layers. At the top, four edge PoPs in Tokyo, Sydney, Mumbai, and Jakarta. When they miss, all four ask the middle layer, one shield cache in Singapore, next to the origin, which sees every PoP's misses. Only the shield asks the bottom layer, the origin in Singapore, which gets about one request per file. A note says that when 2,000 users ask at once, one fetch goes up.Edge PoPsTokyoSydneyMumbaiJakartaShield tierSingapore shieldnear the origincollapsing:2,000 asks,1 fetch upOrigin region: SingaporeOrigin1 request per file
Without the shield, a new file costs the origin one request per PoP. With it, about one. Request collapsing does the same for a burst of users inside one PoP.

Check your understanding · Exercise 4

A site serves 10,000 requests per second through a CDN with a 96 percent hit ratio. Which statements are true? Select all that apply.

Lab: where the milliseconds go

The numbers so far follow one formula. It is worth learning, because in an interview you can rebuild any latency estimate from it in a few seconds.

text
TTFB = DNS
     + 1 RTT(user, PoP)            TCP handshake
     + 1 RTT(user, PoP)            TLS 1.3 handshake
     + 1 RTT(user, PoP)            the request itself
     + on a miss: RTT(PoP, shield or origin) + server time
     + on a hit: about 1 ms of cache lookup

RTT(user, x) is about 10 ms + 2 x distance / (200 km per ms) x 1.65
  (10 ms of last mile; real routes are about 1.65 times the straight line)
RTT(PoP, origin) is the same without the 10 ms: PoPs sit on fast backbone links
With HTTP/3 the TCP and TLS handshakes merge into one RTT. On a reused connection, both handshakes are gone.

Try it below. Pick where the user is, where the nearest PoP is, and where your origin lives. Then switch between a cache hit and a miss, and between a CDN and none. Watch which bar grows.

CDN
CacheProtocol
Time to first byte for a user in Sydney, origin in Frankfurt, PoP in the user's city, cache miss, HTTP/2. DNS (resolver cached): 5 ms. TCP handshake: 10 ms. TLS 1.3 handshake: 10 ms. request to the PoP: 10 ms. PoP to origin (warm): 272 ms. server time: 20 ms. TTFB: 327 ms, compared with 871 ms with no CDN.to scale; user to origin about 16,500 kmDNS (resolver cached)5 msTCP handshake10 msTLS 1.3 handshake10 msrequest to the PoP10 msPoP to origin (warm)272 msserver time20 msTTFB: 327 msno CDN: 871 ms, so the CDN saves 544 ms
Each step waits for the one before it. Handshakes cost the user-to-PoP RTT; only a miss pays the long trip to the origin, and only once.

What the lab shows

  • Handshakes dominate far from the origin. Without a CDN, a user 15,000 km away spends most of the TTFB on handshakes, not on the server.
  • A CDN halves even uncached responses. Ending TLS nearby turns three long trips into one long trip plus three short ones.
  • A hit makes distance to the origin irrelevant. The origin can be anywhere when the response is cached.
  • Origin placement matters for misses. If most users are in Asia, an origin in Singapore cuts every miss for them. That is a backend decision you can argue for from the frontend numbers.
  • A far PoP wastes the CDN. A PoP 2,000 km away, from bad steering, adds about 30 ms to every round trip, so about 100 ms to TTFB. For a user near the origin, that can be slower than no CDN at all.

Think first

A Sydney user has a 10 ms RTT to the local PoP. How much does HTTP/3 save on TTFB for a cache hit, and how much would it save without a CDN, with a 280 ms RTT to Frankfurt?

Edge compute: running your code in the PoP

For years a CDN could only store and serve files. Today most CDNs also run your code in their PoPs, on every request, before the cache or instead of the origin. This is edge compute, and the small functions are called edge functions, workers, or middleware, depending on the vendor.

The main platforms

Limits and features change often; check the vendor's current docs before you design around a number.
PlatformRuns onWhereGood to know
Cloudflare WorkersV8 isolates, Web APIs like fetch, Request, ResponseEvery Cloudflare PoPIsolates start in milliseconds, so cold starts are close to zero. Limits on CPU time and memory per request.
Vercel Routing Middleware and FunctionsNode.js by default (Fluid compute); an edge runtime is still offeredMiddleware globally; functions in the regions you pickMiddleware runs before the cache. In Next.js 16 its file is proxy.ts (formerly middleware.ts). Vercel now recommends Node.js over the edge runtime for most code.
Netlify Edge FunctionsDeno, Web APIsNetlify's edge networkTypeScript out of the box; same Request and Response model.
Amazon CloudFront FunctionsA small JavaScript runtimeEvery CloudFront edge locationSub-millisecond work on headers, URLs, and cookies. No network calls, no body access, and at most 10 KB of code.
Amazon Lambda@EdgeNode.js or PythonCloudFront's regional edge cachesFull Lambda with network access, but real cold starts and fewer locations.
Fastly ComputeWebAssemblyEvery Fastly PoPCompile from Rust, Go, JavaScript and others.

Two designs sit behind these products. Isolate-based runtimes (Workers, Vercel's and Netlify's edge runtimes) run many customers' code inside one process, each in its own sandbox, like tabs in a browser. Starting one costs milliseconds, so cold starts barely matter, but you get Web APIs only, a memory cap (128 MB on Workers), and a CPU time budget per request.

Container or VM-based runtimes like Lambda@Edge run full Node.js with more freedom. The price is the cold start: a new instance can take a few hundred milliseconds to start, which is a lot to add to a request you wanted to make fast.

Good jobs for the edge

The best edge jobs are quick decisions that need only the request itself: its URL, headers, cookies, and the country the CDN detected. No database, no slow API.

  • Redirects and rewrites: /old-pricing to /pricing, / to /en-gb/ by Accept-Language or country, or serving /blog from a different origin.
  • Auth gates: no session cookie on /app/*, redirect to /login before the origin is touched. Verifying a signed token (a JWT checked with a public key) works too, since it needs no database.
  • A/B tests and feature flags: read or set a group cookie, then fetch the cached variant for that group. Both variants stay cacheable, and the user never sees a flicker of the wrong one.
  • Headers: add security headers like CSP and HSTS, or set the cache key for a request.
  • Personalising cached HTML: fetch the cached page and stream it through an HTML rewriter that fills in a small part, like the user's name or currency.
  • Bot and abuse checks: rate limits and blocks before the request costs origin CPU.
ts
export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname !== "/") return fetch(request);

    const cookie = request.headers.get("Cookie") ?? "";
    const known = cookie.match(/ab-home=(a|b)/)?.[1];
    const group = known ?? (Math.random() < 0.5 ? "a" : "b");

    // Each variant is its own URL, so the CDN caches both.
    url.pathname = `/home-${group}`;
    const page = await fetch(new Request(url, request));

    const response = new Response(page.body, page);
    if (!known) {
      response.headers.append("Set-Cookie", `ab-home=${group}; Path=/; Max-Age=2592000`);
    }
    return response;
  },
};
A Workers-style A/B split at the edge. The origin renders two cacheable pages; the edge picks one per user in a millisecond.

The trap: your data is not at the edge

Edge code is close to the user, which means it is far from your database. Say an edge function in Sydney renders a product page and makes three queries, one after another, to a database in Virginia. Each query is a 230 ms round trip: almost 700 ms before the HTML can start. The same code on a server next to the database pays 1 ms per query, and only one long trip back to the user, through the CDN.

This is why platforms that pushed "render everything at the edge" have moved back toward regional servers for data-heavy work. The fixes are: keep data work at the origin; use data that is replicated to the edge (key-value stores, read replicas), accepting that it may be a little stale; or let the platform run the function near the data (Cloudflare calls this Smart Placement).

A decision flowchart for request logic. Start: a request arrives. First question: does it need a database? If yes, run it near the data, for example SSR with queries. If no, second question: is the response the same for everyone? If yes, cache it at the CDN: assets and public HTML. If no, third question: can it be decided from the request alone? If yes, use an edge function: redirects, A/B buckets, auth gates. If no, use the origin or the browser for per-user data.Request arrivesNeeds a database?yesNear the dataSSR with queriesnoSame for everyone?yesCDN cacheassets, public HTMLnoFrom request alone?yesEdge functionredirects, A/B, authnoOrigin or browserper-user dataone page often uses all four
The edge wins only for decisions made from the request itself. Anything that queries data goes near the data; anything shared goes in the cache.

Decision A request needs some logic before it gets its response. Where should that logic run?

At the edge

An edge function or middleware in every PoP.

Pros

  • A few ms from the user; can answer or redirect without the origin.
  • Keeps pages cacheable by moving per-user choices out of the HTML.

Cons

  • Far from the database; every query is a long trip.
  • Limited runtime and CPU; a bug ships to every PoP at once.

At a regional server near the data

SSR (server-side rendering) or an API in the same region as the database, behind the CDN.

Pros

  • Fast queries; full Node.js; easy to debug.
  • The CDN still ends TLS nearby, so only one trip is long.

Cons

  • Every uncached request pays one long user-to-origin trip.

In the browser

Client-side code after the page loads.

Pros

  • No server cost; can use state only the browser has.

Cons

  • Runs after download and parse; can cause flicker or layout shift; cannot protect anything.

What we pick: Use the edge for decisions made from the request alone: redirects, auth gates, A/B buckets, headers, geography. Keep anything that talks to a database near the database. Use the browser for what depends on browser state. A good design often uses all three for one page.

Check your understanding · Exercise 5

Which of these are good fits for an edge function? Select all that apply.

What a frontend should put on a CDN

Short answer: put the whole site behind the CDN, and decide per type of response what the CDN may keep. Even responses that can never be cached gain from the CDN: TLS ends nearby, the connection to the origin is warm, and attacks are absorbed before they reach you. The question is not "CDN or not" but "cached for how long, and by whom". The HTTP caching lesson covers the headers; here is the map.

By type of response

ResponseCached at the CDN?Typical policyWhy
Hashed JS, CSS, and fonts, like app.3f9a1c.jsYes, for a long timeA year, immutableA new build gets a new name, so a copy never goes stale.
Images and videoYesLong if hashed; days if notMost of the bytes; the biggest bandwidth win. Often through an image CDN that resizes per device.
HTML of public pagesYes, briefly, or revalidatedSeconds to minutes at the CDN, with stale-while-revalidateMust change soon after a deploy, because it names the new hashed files.
Public API reads, like a product listYes, brieflyA few seconds to a minuteEven 10 seconds of caching absorbs a traffic spike.
Pages and data for one signed-in userNoprivate or no-storeA shared cache must never serve one user's data to another.
Writes: POST, PUT, DELETENoPassed throughStill gains from the nearby TLS end and the warm origin connection.
An architecture diagram. The browser connects to one host name at a CDN PoP. Inside the PoP: edge logic for redirects and auth gates, then a cache holding hashed assets for a year, images, and public HTML for 60 seconds, then a router by path. On a miss the router sends /assets/* to a storage bucket, /api/* to the API servers, and every other page to SSR servers in one region. Personal data passes through the CDN but is never stored there.browserCDN PoP, one host nameEdge logicredirects, auth gateCacheassets 1 y, HTML 60 sPath routersends misses upstreamOrigins/assets/*storage bucket/api/*API servers/* (pages)SSR, one regionpersonal data passes through, never stored
One host name for everything keeps one connection, one certificate, and one set of cookies. The CDN splits traffic to origins by path, behind the scenes.

One host name, many origins

With HTTP/1.1, sites split files across static1.example, static2.example and so on, to open more parallel connections. With HTTP/2 and HTTP/3, one connection carries everything, and every extra host name costs a DNS lookup, a TCP or QUIC handshake, and a TLS handshake. Today the better default is one host name for the page and its assets, with the CDN routing paths to different origins behind it: /assets/* to a storage bucket, /api/* to the API, everything else to the SSR server.

One host also keeps cookies and CSP simple and means the browser can reuse the connection it opened for the HTML. The exceptions are big, separate services like an image or video CDN, where a second host is worth it; add preconnect for that host so its handshakes start early.

Public library CDNs are not a shortcut any more

An old tip was to load React or jQuery from a public CDN, so users who had visited another site using the same file would already have it cached. That stopped working around 2020: Chrome, Safari, and Firefox now partition the HTTP cache by the top-level site, so a file cached while visiting site A is not reused on site B.

So a public library CDN today only adds a new host name (DNS, handshakes) and a new party you must trust. Bundle libraries with your own code and serve them from your own CDN. If you must load a third-party script, pin the version and add integrity (Subresource Integrity), so the browser refuses the file if its contents change.

Check your understanding · Exercise 6

A news site puts everything behind a CDN. Which policies are sound? Select all that apply.

When it breaks: failure modes, migrations, and multi-CDN

DNS and the CDN sit in front of everything. When they fail, the whole site fails, no matter how healthy the servers behind them are. They also fail in ways that are hard to see from your own laptop, because your resolver and your PoP are not your users' resolvers and PoPs.

DNS migrations and long TTLs

The classic mistake: a team moves to a new CDN on Friday evening by changing the CNAME. The record had TTL 86400, a full day. Users whose resolvers cached the old answer keep going to the old CDN for up to a day, and the team switched the old one off at 18:05. For hours, a large share of traffic fails, and there is no way to purge the world's resolvers.

The safe plan works with TTLs instead of against them.

  1. Lower the TTL early. At least one old TTL before the move (a day ahead for 86400), change the TTL to 60 seconds. Now every cache that refreshes picks up the short TTL.
  2. Run both in parallel. Set up the new CDN fully and test it with a hosts-file entry or a test host name. Both old and new must serve the site correctly.
  3. Switch. Change the record. Within about a minute most users move.
  4. Wait, then retire. Keep the old setup running for days, not minutes. Some resolvers raise very low TTLs to a minimum of their own, and some long-running clients (old Java apps, some IoT devices) cache addresses far longer than told.
  5. Raise the TTL again once the move is stable, to cut lookups.
A timeline of a safe CDN migration over five days. Day 0: the TTL is lowered from 86400 to 60; caches still hold old 86400 copies until day 1. Day 1: the record is switched to the new CDN; from then on caches hold 60-second copies, and the new CDN serves almost everyone within a minute, while the old CDN serves only stragglers. Day 5: the old CDN is retired and the TTL is raised to 3600.what caches holdold 86400 copiesTTL 603600old CDN serveseveryonestragglers onlynew CDN servesalmost everyoneday 0: lower TTLday 1: switchday 5: retire, raise TTLswitch after one old TTL; retire days later
Lower the TTL one old TTL ahead, switch, and keep the old CDN serving for days. The stragglers are resolvers and clients that hold answers longer than told.

Moving to a new DNS provider is slower still, because the NS records live in the TLD zone, often with a two-day TTL that you do not control. Run the old and new providers with identical records for at least that long.

Provider outages

  • DNS provider outage. In October 2016 a huge DDoS (distributed denial of service) attack on the DNS provider Dyn made many big sites unreachable for hours in parts of the world, though their servers were fine. The fix is two DNS providers, both listed in your NS records and serving the same zone, so resolvers try the other when one fails.
  • CDN outage. In June 2021 one customer's valid configuration change set off a hidden software bug at Fastly: about 85 percent of its network returned errors, and many major news and government sites went down with it until most of the network recovered within 49 minutes. In July 2019 a single bad firewall rule made Cloudflare's servers spend their CPU on a regular expression and fail requests worldwide for 27 minutes. One provider is one point of failure.
  • Your own edge code. A bug in an edge function or a CDN rule ships to every PoP within seconds. That is a global outage you caused. Roll edge changes out gradually where the platform allows it, and keep a fast rollback.
  • Origin outage. If the origin is down, the CDN can still serve what it has. stale-if-error lets cached pages keep working for a while, so a static marketing site can survive a full origin outage.
  • Certificate expiry. Managed edge certificates renew themselves; a certificate you uploaded by hand does not. Put the expiry date in monitoring.

Multi-CDN and failover

Large sites use two or more CDNs at once. A DNS layer in front, often a traffic steering service with health checks, decides which CDN each user gets. If one CDN fails health checks, the DNS answers switch to the other, within a short TTL. Some sites also split traffic by region or by price, sending each country to whichever CDN measures fastest there.

A state machine for DNS-based failover between CDN A and CDN B. Healthy: all traffic on CDN A. When health checks fail, it moves to Degraded, which is watching. If checks pass again, it goes back to Healthy. After three failures in a row, it moves to Failed over, where DNS points at CDN B. When A is healthy again, it moves to Recovering, which shifts traffic back slowly, and after 10 stable minutes, back to Healthy.Healthyall on CDN ADegradedwatchingFailed overDNS points at BRecoveringshift back slowlychecks failpass again3 in a rowA healthy againstable 10 mina DNS TTL of 30 to 60 s sets how fast users follow
Each transition changes DNS answers, so a short TTL decides how fast users follow. Shifting back slowly avoids flapping and gives A's cache time to warm.

Decision Should the site use one CDN or several?

One CDN

All traffic through one provider, with its own anycast or steering.

Pros

  • Simplest; full use of the vendor's features and edge runtime.
  • One cache to warm, one config, one bill.

Cons

  • A provider outage is your outage.

Active and standby

One CDN takes traffic; a second is configured and ready.

DNS health checks switch on failure.

Pros

  • Survives a full provider outage in minutes.

Cons

  • The standby's cache is cold when it takes over, so the origin gets a burst.
  • Config must be kept the same on both, or the failover breaks things.

Active and active

Traffic split between CDNs all the time, by region, weight, or measured speed.

Pros

  • Both caches stay warm; best speed per region; competing quotes on price.

Cons

  • Only features both CDNs share; edge code must run on both runtimes.
  • More work: two configs, two sets of logs, two certificates.

What we pick: Most products should run one good CDN and spend the effort on short TTLs, stale-if-error, and a tested origin. Multi-CDN pays off when an hour of downtime costs more than a team's time to keep two setups in step: large media, retail, and payments sites. If you go multi-CDN, keep edge logic small and portable.

How you notice and debug

  • dig +short www.recipes.example from several networks, or a public multi-location DNS checker, shows what different resolvers see and with how much TTL left.
  • curl -sI shows the CDN's response headers: a cache status like x-cache: HIT or cf-cache-status: MISS, the age of the cached copy, and often which PoP answered.
  • Server-Timing headers from the edge and origin let real-user monitoring split TTFB into edge time and origin time.
  • Real-user monitoring grouped by country and by PoP shows a bad PoP or bad steering that synthetic tests from one city miss.

Check your understanding · Exercise 7

You must move www from CDN A to CDN B. The CNAME has TTL 43200 (12 hours). Which steps are right? Select all that apply.

In real products

Every big site uses these pieces, but they arrange them differently, depending on what they serve and where their users are.

  • Cloudflare runs one anycast network in more than 330 cities. Every customer's site is reachable from every PoP, and Workers run in all of them. Its public resolver 1.1.1.1 is anycast on the same network, which is why it answers in a few milliseconds from most places.
  • Netflix goes one step closer than a PoP. Its Open Connect program places cache servers inside internet providers' own networks, filled overnight with the shows people in that area are likely to watch. Most video bytes never cross the wider internet at all.
  • Wikipedia serves readers from a few caching data centres on several continents, while its databases and editing live in the US. Most page views are anonymous reads, so the hit ratio is very high; signed-in users mostly skip the page cache and get pages built for them.
  • Next.js on Vercel shows the frontend view: hashed files under /_next/static/ get year-long caching at the edge, statically generated and ISR (incremental static regeneration) pages are served from the edge cache, the middleware file (proxy.ts since Next.js 16, middleware.ts before) runs before the cache for redirects and auth, and server rendering that needs data runs in a region near the database.
  • Video streaming in general (HLS and DASH) splits video into small segment files, a few seconds each, with fixed URLs. To a CDN, a live stream is just a fast stream of new, cacheable files: one origin fetch per segment per shield, then millions of hits.

The common shape

Look past the brand names and the same layout repeats. DNS with a short TTL points at a CDN. The CDN ends TLS near the user, runs a little request logic, and answers most static requests from cache.

A shield protects the origin. Data-heavy work happens in one or a few regions near the data, and the CDN carries even those responses over warm connections. When you draw a frontend architecture, this is the default to start from and then adjust.

Think first

A startup with users only in India hosts everything in a US region. Their pages are slow in India. They ask whether to move to edge rendering. What do you suggest?

Using it in a system design interview

Frontend system design interviews rarely ask "explain DNS" on its own. These ideas come up inside a bigger design: a news site, an e-commerce page, a video player, a global dashboard. Bringing them up at the right time, with numbers, shows that you think about the user's whole request, not only the components.

When to bring it up

  • When the prompt says global users or names countries: talk about RTT, a CDN, and where the origin should live.
  • When you discuss performance or Core Web Vitals: a CDN is the first fix for TTFB, and TTFB is the floor under LCP (Largest Contentful Paint).
  • When you choose a rendering strategy: static and ISR pages live at the edge; SSR pages need a region near the data; middleware runs in between.
  • When the design has personalised pages: explain how you keep the shared part cacheable and move the personal part to the edge or the client.
  • When asked about reliability: DNS TTLs, stale-if-error, and, for a very large product, multi-CDN.

What to draw

One line of boxes is enough: browser, DNS, CDN PoP (with "TLS, cache, edge logic" written inside), shield, origin (SSR and API), database. Then write the cache policy next to each kind of response: hashed assets for a year, HTML for seconds with revalidation, API reads for a few seconds, personal data private. Add one RTT number for a far user, with and without the CDN.

LevelWhat a strong answer includes
JuniorStatic files on a CDN with hashed names and long caching; knows that a nearby server is faster and why.
MidRTT math for a far user; TLS ending at the edge; HTML vs asset caching; hit ratio and what lowers it; what not to cache.
SeniorAnycast vs DNS steering and their failover; shielding; edge vs regional compute and data gravity; TTL plans for migrations; multi-CDN trade-offs; monitoring TTFB by PoP.

Check your understanding · Exercise 8

An interviewer asks how you would make a product page fast for users worldwide. Which points belong in a strong answer? Select all that apply.

Summary

  • Distance sets a floor: about 1 ms of RTT per 100 km, and every handshake costs one RTT. A far user pays it three or four times before TTFB.
  • DNS walks from the stub to a recursive resolver, which asks root, TLD, and authoritative servers and caches each answer for its TTL, including "does not exist" answers.
  • CDNs send users to a nearby PoP by DNS steering, anycast, or both. Anycast fails over in seconds; DNS steering waits on TTLs.
  • Ending TLS at the PoP and reusing warm origin connections makes even uncached responses much faster. Lock the origin so only the CDN can reach it.
  • Hit ratio drives origin load: 95 to 99 percent is five times fewer origin requests. Shielding and request collapsing protect the origin as PoPs multiply.
  • Edge functions are for quick decisions from the request alone. Data-heavy work belongs near the data.
  • Put the whole site behind the CDN; cache hashed assets for a year, public HTML briefly, and personal data never.
  • Lower DNS TTLs before any migration and keep the old target running for days; consider a second DNS provider or CDN only when downtime costs justify it.

In the interview

Questions interviewers ask about this. Answer each out loud first, then compare.

Question 1

Walk me through what happens when a browser resolves www.shop.example for the first time.

Question 2

How does a CDN make a page faster for a far-away user when the HTML cannot be cached?

Question 3

Anycast or DNS-based steering: what is the difference, and how does it change failover?

Question 4

When would you run logic in edge middleware, and when would you keep it at the origin?

Question 5

We are switching CDNs next week. What could go wrong with DNS, and how do you plan it?

References

Read next