OpenNext on Cloudflare: 7.87M R2 reads from cache hits and 10M Worker requests from a prefetch loop
Meathill debugs two back-to-back cost spikes on a Next.js 16 site on Workers: background R2 reads on every RegionalCache hit, then an infinite _rsc prefetch loop from OpenNext cache interception, with the config changes that stopped each.
- Products
- WorkersR2
- Source
- Author experienceMeathill’s blog (meathill.com)
- Author
- Meathill (@meathill1)
Key points
- With about 2,300 daily visitors, R2 showed 19,000 Class A and 7.87 million Class B operations. The author reads a ratio above 400:1 as reads on cache hits rather than misses, and found Class B closely tracking zone requests.
- Cause: under Next.js 16, OpenNext's withRegionalCache defaults shouldLazilyUpdateOnCacheHit to true, so each hit triggers a background R2 read via waitUntil. Short s-maxage (600 s home, 1,800 s inner pages) and hundreds of independent PoPs amplified it.
- R2 fixes: set shouldLazilyUpdateOnCacheHit to false, move the incremental cache to its own bucket with a lifecycle rule expiring incremental-cache/ after 7 days, cut image sizes to five, and raise s-maxage and revalidate to 86,400 s.
- Two days later Worker requests passed 10 million and observability usage spiked. He traced the endless _rsc prefetches to enableCacheInterception: true (opennextjs-cloudflare issue 1348), turned it off, and added prefetch={false} to low-intent links in 35 components, cutting first-screen prefetches by over 70%.
- Official docs (rechecked 2026-10-14): GetObject and HeadObject are R2 Class B operations; lifecycle rules usually delete expired objects within 24 hours and deleted objects stop billing; Workers Paid includes 10 million requests a month, then $0.30 per million.
Original sources
Published
OpenNext on Cloudflare: 7.87M R2 reads from cache hits and 10M Worker requests from a prefetch loop
Open original sourceMeathill debugs two back-to-back cost spikes on a Next.js 16 site on Workers: background R2 reads on every RegionalCache hit, then an infinite _rsc prefetch loop from OpenNext cache interception, with the config changes that stopped each.
Live post while debugging: R2 Class B reads had exploded and the author was tracking down the cause.
Read on 𝕏Meathill
@meathill1 · Original 𝕏 post
艹,next.js 真的有 bug,16.3.x 之后,会死循环 prefetch,昨天的流量直接就把我的 Worker 额度全线打爆了…… https://t.co/NS8PjNxk9T
The author shares the write-up of the R2 read and Worker request incidents on 𝕏.
Read on 𝕏Meathill
@meathill1 · Original 𝕏 post
https://t.co/jDUdD5pUz6 好久没写博客,最近踩一大坑,写出来给大家当前车之鉴。前几天关于AMD免费AI API的文章侥幸成为爆款,把https://t.co/CZZ6zVzqV0网站不够扎实的基础暴露的一塌糊涂。因为缓存设置不当加上中招next.js无限循环prefetch的bug,所有Worker额度均被打爆。希望对大家有帮助。
Follow-up: once the free Class A quota was used up, the ISR cache on R2 cost him more than the Worker itself.
Read on 𝕏Meathill
@meathill1 · Original 𝕏 post
完蛋,上次的 bug 把这个月的 A 类操作额度也用完了,结果现在 ISR 页面缓存的价格反而比 worker 更贵……今天只好停掉 ISR 试试看,如果明天成本能降下来,以后低访问量的网页就不走 ISR 缓存了。
More to read
Four layers of cost protection for small Cloudflare projects
David Z (@davezfr) writes an X article for vibe coders on budget alerts, stop conditions for paid paths, automatic pausing, and letting a personal agent verify and pause.
Yan Zhu (picturepan2): about $400 from a D1 row-reads spike.
Yan Zhu (@picturepan2) says he also hit an about $400 Cloudflare bill the previous month when D1 database row reads spiked. He quotes the shmily7 Durable Objects thread for context and does not report a refund or support outcome.
Budget alerts
Cloudflare documents account-wide spend alerts and their notification limits.