Guide · Speed
Why your Vercel ISR reads and CDN requests run far higher than your visitors
They don’t count people. A CDN request is one file, and one visit asks for dozens. An ISR read is counted in 8 KB pieces of a cached page, so one big page can cost dozens of read units. A few people a day can add up to hundreds of thousands of both.
A real example: 594K ISR reads from a few dozen people a day
A small Next.js 15 site (App Router) on Vercel’s free Hobby plan, over one month, 2 October to 1 November 2026. Its owner asked: “I am getting a lot of ISR reads and slightly fewer CDN requests, and the number doesn’t match the people coming to the app.” Vercel’s dashboard and the site’s own analytics showed:
Those 2,418 page views are a few dozen people a day. That analytics only counts visitors who agreed to it, so the real number is higher. Even so, half a million requests and 594K read units from a site this size needed explaining. Here’s what explained them.
Why are my CDN requests so much higher than my real visitors?
Because a CDN request is one file, not one person. On the example site, one visit to the home page, without scrolling, made 46 requests: the HTML, JavaScript chunks, fonts, analytics beacons, a poll that checks for a new version, and 9 prefetches of other pages.
A rough rule: CDN requests ≈ visits × (files + prefetches + beacons) per page. Vercel’s Hobby plan includes the first 1,000,000 CDN requests a month, so this site used about half of that with a few dozen people a day.
Why does next/link prefetch so much?
In production, Next.js’s <Link> prefetches a page as soon as its link scrolls into view. For static routes it fetches the full route, with all its data (Next.js docs). Each prefetch is a request ending in ?_rsc=.
On the example site, the 9 prefetches from one landing were 3.2 MB of page data. The site had no prefetch={false} anywhere, and most visitors left without clicking any of those links, so most of that was downloaded for nothing.
Why are my ISR reads higher than my CDN requests?
Because ISR reads aren’t counted per request. Vercel measures them in 8 KB units: one read unit is 8 KB read from the ISR cache (Vercel’s docs). A 600 KB page costs about 75 read units each time it’s served from the ISR cache.
Reads from the CDN cache are free. Units only add up when a request misses the CDN cache and falls through to the ISR cache. But with big pages, a small share of misses is enough: about 8,000 misses on 600 KB pages make 594K read units.
A rough rule: ISR read units ≈ cache misses × (page size ÷ 8 KB).
Why was every page so big?
Every cached page on the example site was about 600 KB, and the home page 762 KB. After brotli compression, a browser downloaded only about 60 KB. That compressed number is the one Lighthouse and load tests look at, so nobody noticed. Vercel’s docs don’t say whether read units are counted on the compressed or the unpacked size. On this site, Vercel’s dashboard showed the cached pages at their unpacked size.
What was inside the 616 KB privacy page:
- 183 KB of CSS in a
<style>tag. - The same 108 KB of Tailwind CSS twice more, inside the data Next.js sends for client-side navigation (the
self.__next_f.pushlines). - 76 KB of design-system CSS, also in that data.
- About 140 KB of actual page.
About three quarters of every page was the same CSS, repeated.
Does experimental.inlineCss cost me money on Vercel?
It can. experimental.inlineCss puts your stylesheet in a <style> tag in every page, instead of a separate file, to save a render-blocking request on the first visit. Next.js lists the trade-offs itself: inlined styles can’t be cached separately from the HTML, every page load downloads the same CSS again, and styles are duplicated, “once within <style> tags for SSR and once in the RSC payload” (Next.js docs).
All of that CSS is part of the cached page, so it’s part of every ISR read. It travels in prefetches too: on the example site, each prefetch carried about 370 KB of it.
Do deploys make ISR reads go up?
They can. Each new deployment uses its own ISR cache and its own CDN cache, and doesn’t reuse the previous deployment’s (Vercel’s docs). So after every production deploy, the first request for each page in each region misses the CDN cache and is read from the ISR cache.
The example site deployed once or twice a day, so its caches were often cold. Automated checks that run against production right after a deploy hit those cold caches too.
Are bots eating my quota?
Check before you assume. On the example site, bots (Googlebot, AhrefsBot, Bingbot and OpenAI’s crawlers) made about 5% of CDN requests. They weren’t the gap. Blocking search engines and AI crawlers to save requests would cost you far more in people who never find you.
How do I find which routes cost the most?
- In Vercel, open Observability, then ISR, then Routes, and switch the view to Bytes. It shows the size of each cached page. That’s where the example site’s 600 KB pages showed up.
- Count your prefetches: open your live site with Chrome’s developer tools on the Network tab, reload, and type
_rscin the filter box. Each row is a prefetch. In the Network settings, turn on big request rows to see each one’s downloaded size and its unpacked size. - Compare the sizes of one page:
curl -sL yourapp.com | wc -cprints the unpacked size in bytes. Add-H 'Accept-Encoding: br'to see what browsers download. A big gap means a big page that looks small in speed tests.
How do I bring the numbers down?
The example site’s owner tried the first two fixes on 2 November 2026: two production builds of the same code, tested on a phone profile in Lighthouse, middle result of 3 runs. The read units below are worked out from the page sizes, not yet from a month of Vercel bills.
- Turn off inlineCss. The CSS became two separate files (24 KB after compression) that the browser downloads once and keeps. Each cached page went from about 600 KB to about 125 KB, so a cache miss costs about 17 read units instead of 77, and a prefetch about 10 instead of 46: roughly 77% fewer. All the prebuilt pages together went from 59.5 MB to 10.8 MB, so the deployment itself got smaller too.
- It didn’t make the site slower. The usual worry is a render-blocking stylesheet on the first visit. Here the Lighthouse scores went up slightly (89, 86 and 93 to 91, 87 and 95 on three pages), the main content appeared 150 to 300 ms sooner (home page 3.75 s to 3.46 s), and the first paint stayed the same. The home page download fell from 833 KiB to 577 KiB.
- Limit prefetching where links are rarely tapped. A visit made 4 prefetches on a phone (7 after scrolling), and 6 on a desktop (25 after scrolling to the footer). Don’t turn prefetching off everywhere: on a slow phone, a tap to a page that wasn’t prefetched took 1.48 s, against 0.06 s for one that was, because a prefetch loads the page’s JavaScript as well as its data. Keep it for your main navigation. For footers and big card grids, set
prefetch={false}, and if you like, callrouter.prefetchonpointerenter. On phones, prefetching ontouchstartgives only about 100 ms of head start, so it barely helps there. - Make the CSS smaller. Remove unused Tailwind classes and design tokens. Every page and every prefetch gets smaller.
- Batch production deploys. Each deploy starts with cold caches, so fewer deploys means fewer misses.
The lesson from this site: inlining CSS pays off while the CSS is small. Once it’s large, and the framework copies it into the page data too, every page and every prefetch carries it, and those bytes cost more than the one request they save. Fix the CSS first, and every prefetch that’s left becomes about five times cheaper, so prefetching matters much less.
A ready-made fix prompt for a heavy page is part of Pro, coming soon. What we found stays free.
What this can’t tell you
We check your site from outside, like a visitor. We measure the size of your page’s HTML after it’s unpacked, which is the size this guide is about. We don’t see your Vercel usage, your ISR cache, how often you deploy, or what your links prefetch. The numbers here come from one site in one month; yours depend on your pages and your traffic. Vercel’s prices and allowances can change, so check their pages for your plan.
Related
- ChatGPT can’t see your app: why AI assistants get a blank page
- Why your AI-built app isn’t on Google, and how to see what Google sees
Sources
- Vercel: ISR limits and pricing and Incremental Static Regeneration (vendor, read 2 Nov 2026)
- Vercel: Hobby plan (vendor, read 2 Nov 2026)
- Next.js: inlineCss and Link (vendor, read 2 Nov 2026)