Skip to content

Build1 publisher3 min readPublished

A build step instead of a backend: 1,025 records, 8 locales, no runtime API

A dev.to build log mirrors a public REST API into static JSON and ships it to Cloudflare's edge. The failure mode disappears; the request count and the staleness question do not.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying A build step instead of a backend: 1,025 records, 8 locales, no runtime API
Generated illustration

What happened

  • The author reports building an encyclopedia web app with 1,025 entries, 8 languages, and sub-second load times without a traditional backend.
  • Stack: Next.js 15, TypeScript, Tailwind CSS, next-intl, Cloudflare Pages.
  • Rather than calling the public API at runtime, the author pre-fetches all data and stores it as static JSON in /public/api/v2/, which Next.js serves as static assets and Cloudflare Pages distributes.
  • Stated motivations: hitting the API on every request would be slow and rate-limited; a traditional backend felt like overkill for essentially static data; multilingual support was a must because the audience is global.
  • Stored per entry: core data (stats, types, abilities, moves, dimensions); species data (flavor text, egg groups, habitat, generation); evolution chains as full trees with trigger conditions; type matchups covering damage relations for all 18 types.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A developer has published a build log for a reference site with 1,025 entries across 8 languages that has no runtime data backend: the public REST API is fetched once at build time, written to static JSON under `/public/api/v2/`, and served from Cloudflare Pages [1][2][3]. The consequence is the interesting part, because a whole class of production failures gets deleted rather than mitigated: according to the author there are no API keys, no rate limits, and no external dependency at request time [6].

The reasoning is stated plainly. Hitting the upstream API on every request would be slow and rate-limited, a conventional backend was overkill for data that is effectively static, and the audience is global so multilingual support was mandatory [4]. The stack is Next.js 15, TypeScript, Tailwind, next-intl and Cloudflare Pages [2]. Per entry the mirror stores core data (stats, types, abilities, moves, dimensions), species data (flavor text, egg groups, habitat, generation), full evolution chains including trigger conditions, and damage relations for all 18 types [5]. That is at least 2,068 JSON files before evolution chains are counted: one entry file and one species file for each of 1,025 records, plus one per type [3]. The payoff beyond latency is auditability - the data sits in version control, so a diff shows exactly what changed upstream [7].

The cost shows up on the client. The author reports that loading all entries at once would freeze the browser, so the grid fetches in batches of 50 with a progressive `setEntries` call after each batch, then uses an Intersection Observer with a 200px root margin to reveal 50 more cards per scroll [9][10][11]. Filtering is all local: 9 generations, 18 types, a base-stat-total range, legendary and shiny toggles, and text search by name or number [8]. At 50 per batch, a full unfiltered pool takes 21 rounds [1], and because each entry is fetched by id through a per-id cache, a cold visit to the index can issue up to 1,025 separate JSON requests [2]. Cheap against a CDN with 300-plus edge locations [6], but a single prebuilt index file carrying id, name, types and stats would do the same job in one request. The grid only needs those four fields [11].

Two things in the write-up are softer than the headline. The detail pages use server-side rendering to fetch entry, species and evolution chain data [12], so "zero backend" means no data backend, not no server-side compute. And the sub-second load time is the author's own figure with no measurement method given [1].

What to watch: rebuild cadence, which the post does not specify. A build-time mirror is only as fresh as its last deploy, and the freshness policy is the thing you are actually buying with this trade. Watch build duration too, since the fetch-once step scales linearly with record count and any locale fan-out. The post describes localized flavor text as a field inside the species data rather than as separate per-locale mirrors [5], so whether 8 locales multiply the file count or not is unresolved in the source. If it does multiply, the same 1,025 records become 8,200 files [4], and the build step becomes the bottleneck the backend used to be.

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories