DEV Community

Daniel Pertu
Daniel Pertu

Posted on

Our homepage renders in Washington for a visitor in Frankfurt, because two pages are force-dynamic and nobody ever chose a region

Everything below is measurable with curl and dig from anywhere, against pub-trivia.app, with no account and no cooperation from us. That is the point of the exercise: this is the layer of your product that a stranger can audit better than you can, because you are inside it.

The chain in x-vercel-id

curl -sI https://pub-trivia.app/ | grep -i 'x-vercel\|cache-control'
Enter fullscreen mode Exit fullscreen mode
cache-control: private, no-cache, no-store, max-age=0, must-revalidate
x-vercel-cache: MISS
x-vercel-id: fra1::iad1::bcs79-1793356779377-927d65a30a30
Enter fullscreen mode Exit fullscreen mode

Two region codes in that id. fra1 is the edge that accepted my connection, Frankfurt, because that is where I am. iad1 is where the work happened, which is Washington DC.

Now the same thing for a guide page:

age: 952146
cache-control: public, max-age=0, must-revalidate
etag: "nhaiw8tnbl1oru"
x-nextjs-prerender: 1
x-nextjs-stale-time: 180
x-vercel-cache: HIT
Enter fullscreen mode Exit fullscreen mode

Prerendered, cached, 952,146 seconds old, which is eleven days. It never goes to Washington at all. A static asset gets an even shorter id with one region in it, fra1::..., plus a one-year immutable cache.

What that costs, measured

Three samples each, after a warm connection:

page cache TTFB
/faq HIT 0.108, 0.113, 0.114
/features HIT 0.107, 0.119, 0.121
/guides/how-to-host-a-pub-quiz HIT 0.119, 0.134, 0.136
/pricing MISS 0.243, 0.261, 0.389
/ MISS 0.264, 0.266, 0.996

So the cached pages answer in about 110 to 135ms from a few hundred kilometres away, and the two uncached ones take 240 to 390ms, with a cold one approaching a second. The gap is roughly an extra 130 to 250ms, which is about what a transatlantic round trip plus a render costs.

The two slow pages are the homepage and the pricing page. Of all 72 URLs in our sitemap, those are the two we would least like to be the slow ones.

Why those two, and why Washington

The why-those-two is deliberate and written down. Exactly two page files in the repository carry export const dynamic = "force-dynamic", and they are app/page.tsx and app/pricing/page.tsx. Those are the two pages that show a price, and the price is resolved from the visitor's country, which arrives as a request header. A page that must read a per-visitor header cannot be a cached artifact. That trade was made on purpose: a German visitor sees euros rather than pounds, and the cost of that is the page cannot be prerendered.

The why-Washington is not deliberate at all. There is no vercel.json in the repository. The function region is the platform default, and the default is iad1. Nobody sat down and decided that a product sold to pubs in the United Kingdom should execute its per-request renders in Virginia. It is simply what you get when you never open that setting, and the only reason it is visible at all is that the response header prints it next to the edge that took the request.

The fix is a one-line region setting and a redeploy. The reason it was never done is that nothing in a local development loop, a Lighthouse run from a laptop, or a dashboard chart reads "this render crossed an ocean". The header does, and only if you look.

The rest of the outside surface

No IPv6. dig AAAA pub-trivia.app returns nothing. The apex has two A records on Vercel anycast space with a TTL around 1,300 seconds, and nameservers at vercel-dns.com. Any visitor on an IPv6-only mobile network reaches us through their carrier's translation layer or not at all.

No HTTP/3. There is no alt-svc header on any response and no HTTPS resource record in DNS, which are the two ways a browser learns that QUIC is on offer. Every connection is HTTP/2 over TCP.

Neither of those is a decision we made either. They are both platform behaviour, and that is worth saying plainly rather than pretending they are considered positions. The useful knowledge is that I now know which parts of our transport story are ours and which belong to the host.

TLS. A Let's Encrypt certificate, issued 17 October, expiring 15 January, with exactly one name on it: the apex. Ninety days, renewed by the platform, nothing for us to do.

www. www.pub-trivia.app resolves to a different pair of addresses, has its own certificate, and answers:

HTTP/2 307
location: https://pub-trivia.app/
Enter fullscreen mode Exit fullscreen mode

A 307, which is a temporary redirect. A redirect from the www host to the canonical host is about as permanent as a decision gets, and 308 is the code that says so. This one is cosmetic, because everything that matters already names the apex: every canonical tag, every sitemap entry, every internal link. Plain http:// does answer 308, correctly.

Try it on your own site

curl -sI https://your-site/ | grep -i 'x-vercel-id\|x-vercel-cache\|age'
dig AAAA your-site
curl -sI https://your-site/ | grep -i alt-svc
Enter fullscreen mode Exit fullscreen mode

Three commands. The first tells you where your HTML is actually built and whether it was built again for this visitor. If the id has two region codes in it, the second one is where your code ran, and if that is not near your customers, check whether you ever chose it.

For ours, the honest summary is that 70 of 72 pages are doing the right thing by being boring files at the edge, two pages buy a localised price with about 130ms, and the region that 130ms is measured against was never picked by a human. Compare a cached page with the pricing page in your own network tab and you will see the same split from wherever you are.

Top comments (0)