Build1 distinct publisher3 min readUpdated
A wallpaper site's post-mortem on serving 70,000-plus 4K masters through Next.js 15 shows the optimizer failing on Referer checks and edge CPU ceilings, not on throughput.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The team behind Zenith Walls has published an account of serving a catalog of more than 70,000 4K and 8K images through Next.js 15's App Router, sourced from several external CDNs plus their own Cloudflare R2 bucket [1][16]. The useful part is not the fix but the failure mode: according to the write-up, `next/image` broke because it fetches like a server, not because it was slow [4].
Three walls, in order of how quickly you hit them. First, the Referer check. Many image hosts protect bandwidth by inspecting the HTTP `Referer` header, and when the Next.js optimizer fetches server-side it sends a bare request with no browser context, so the upstream returns 403 or a 0-byte body and the user gets an empty card [5]. That is not a performance regression, it is a blank grid. Second, CPU. On an edge deployment the execution window is roughly 10ms to 50ms, 10ms on Cloudflare Workers, and running Sharp or WASM libvips against an 8K source inside that handler times out immediately [6]. Third, if you dodge the optimizer by pointing the browser at a public R2 bucket, browsers enforcing `Cross-Origin-Resource-Policy: same-origin` can block the fetch anyway [7].
The scale explains why per-request transformation was never going to work. The masters are uncompressed files of 10MB to 25MB [2], so 70,000 of them is somewhere between roughly 700GB and 1.75TB of source bytes [1], and a browser asked to decode dozens of 4K bitmaps in parallel locks the tab [3].
Their answer is to stop treating URLs as data. Every database `image_url` passes through a deterministic chain: `getDisplayUrl` strips thumbnail artifacts and normalizes CDN hostnames, `getProxiedUrl` rewrites to `/api/proxy` with dimensions and a source ID, and the edge route injects headers, handles R2 bindings and caching [8]. Grid tiles request width 400 at quality 75; the download button uses a separate function that returns the untouched full-resolution master [9]. The proxy itself streams rather than buffering multi-megabyte bodies in memory [10], rejects non-allowlisted hostnames as an SSRF guard before opening a connection [11], and for R2 URLs fetches through the internal bucket binding, which skips the public internet round trip and the CORP problem in one move [12].
Two things to read carefully. The published portion of the route describes an allowlist check, an R2 binding and a piped response stream with cache headers, and shows no resize step [15]; if nothing transforms at the edge, then `width` and `quality` are cache-key decoration and the actual byte savings come from `getDisplayUrl` picking a smaller upstream asset [9][10]. And the claimed outcome, slashed LCP and no blank-loading flashes without ballooning infrastructure bills, arrives without a single before-and-after number [14], on a site whose own diagnosis names CLS and LCP as the thing being destroyed [17].
Watch the cache headers, because they are the real bet: 7 days in the browser, 30 days at the shared and CDN layer, 1 day of stale-while-revalidate [13][2]. A 70,000-item catalog has a long tail, and a 30-day shared TTL only pays if requests repeat; the `immutable` directive on top of it means the practical way to correct a bad response is to change the URL rather than purge [3]. The allowlist is the other recurring cost: every new upstream source is now a code change in the proxy [11].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
Zenith Walls built a catalog of over 70,000 4K and 8K images sourced across multiple external CDNs and their own Cloudflare R2 object storage.
The source images are uncompressed files of 10MB to 25MB each.
The next/image optimizer falls apart when upstream CDNs reject requests missing Referer headers.
Many external image hosts check the HTTP Referer header to protect bandwidth; when next/image optimizes server-side it makes a bare fetch without the browser's context, and the CDN returns a 403 Forbidden or a 0-byte response, leaving the user staring at an empty card.
Every wallpaper URL flows through a deterministic normalization pipeline: getDisplayUrl strips thumbnail artifacts and normalizes CDN hostnames, getProxiedUrl routes through /api/proxy with source ID and dimensions, and the edge proxy route at /api/proxy injects headers and handles R2 bindings and edge caching.
Grid display images are requested via getProxiedUrl with width 400 and quality 75, while explicit downloads use getFullResolutionUrl, which always delivers the untouched full-resolution master.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Mechanisms shown in code, outcomes unmeasured
The technical claims are unusually concrete for a single blog post - the proxy route, cache headers, and URL helpers are quoted as source - which makes the described architecture inspectable. But everything rests on one self-reported item: the platform limits (10ms Workers CPU, CORP blocking, Referer-based 403s) are asserted without logs, traces, or vendor references, the key allowlist function is not shown, and the claimed performance and cost outcomes have no before/after data.
One self-disclosed production deployment
There is a concrete production use - the operator's own site serving a 70,000-plus image catalog through the pipeline - but adoption stops there. No other team, library, template, or vendor is shown using the pattern, there are no downstream forks or reuse signals, and the deployment itself is only attested by its author.
Framing outruns the published proof
The story's strong framing - the optimizer as an 'outage', LCP 'slashed', sub-20ms worldwide responses, bills not ballooning - is not backed by a single number, and the code that is supposed to replace optimization performs no image transformation at all, only header injection, streaming, and caching. The underlying failure modes are credible and specific, which keeps the gap moderate rather than severe, but a reader is being sold a measured win that was never measured.
Vendor-authored promotion of its own product
The post is published by the Zenith Walls team on a developer platform, names and links its own product throughout, and positions the team as having solved a hard scaling problem. That is a straightforward marketing and recruiting incentive to present the architecture favourably and omit unresolved gaps such as missing metrics, the unshown allowlist, and the terms-of-service questions around proxying third-party CDN images with an injected Referer. No adversarial or independent review is present to offset it.
Confident on design, not on results
Confidence is moderate: the architectural facts are well specified and quoted, so the description of what was built is likely accurate. Confidence in the causal and quantitative story - that this is why next/image failed and how much it improved - is low, because there is one self-interested source, no measurements, and no corroboration.
build
Pin `formats` before you take the next/image v4 bump1 distinct publisher
build
A build step instead of a backend: 1,025 records, 8 locales, no runtime API1 distinct publisher
build
Tailwind v4 moves your tokens into CSS. The token name is now the API.1 distinct publisher
build
Prisma v7 stops seeding for you, and the pooled URL will not finish the job1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 18, 2026