Choosing zfb
Who zfb is for, how the three run shapes — static build, SSR on Cloudflare Workers, and a local content server — map onto real projects, and where the scaling sweet spot is.
What this page covers
Whether zfb is the right tool for your project — including an honest look at what it is not good at. Cross-linked toThree ways to run zfb, thearchitecture overview, thegetting-started guide, and the scaling note in theREADME.
zfb is a focused tool. It solves a specific problem well, and it deliberately leaves other problems to other tools. This page maps that out so you can make the call before you invest time.
Who this is for
zfb is built by one developer for the things that developer is making: zudo-doc documentation sites, CCResDoc, and the sites those serve. It is published because someone who thinks the same way may want it — people who want to drop a content engine into a Tauri-style app the way CCResDoc does, and people who want SSG and SSR as small composable parts rather than a whole framework that owns the site.
The origin story is plain. At the start of the project, everything felt big. Next.js is big. Astro is lighter, but it supports a large ecosystem of external libraries this project did not need. Today many small features can be built with AI assistance quickly and at high quality, so a library is no longer the default answer for each of them. "No need" would overstate it — but those pieces are better kept under your own control than under someone else's release schedule. A tiny core CLI matched that. The full argument for recipes over plugins lives in Design philosophy.
So this page is not trying to talk you out of Astro or Next.js. If one of them fits your project, use it. zfb is here for the projects where the interesting work happens somewhere other than page rendering.
When zfb fits well
zfb runs the same Request/Response application in three shapes, and most projects lean on one of them. Three ways to run zfb walks through all three in detail; this section is the fit test for each.
Static build
A strong match when your source of truth is Markdown or MDX files in a repository and you want a fast, deterministic build step that turns them into static HTML. zfb's entire architecture is shaped around this case.
Per-page dependency graph. With hundreds of pages you do not want a full rebuild on every edit. zfb tracks which source files each page depends on and rebuilds only the affected pages when something changes. The dependency graph (crates/zfb-graph) is a first-class part of the engine, not a bolt-on.
Workers Static Assets drop-in. Static output from zfb build drops directly into a Workers Static Assets deployment (Pages-compatible). There is no server runtime to manage, no serverless function to configure, and no adapter layer. The built dist/ is the deployment artifact.
SSR on Cloudflare Workers
A strong match when some routes have to run at request time and your target is Cloudflare Workers. Routes that opt out of prerendering with prerender = false are served by @takazudo/zfb-adapter-cloudflare, and Cloudflare bindings reach any page component through getCloudflareContext() without prop-drilling.
The bundle contract does not change between the two shapes: the worker bundle the build drives in an embedded V8 isolate is the same shape that deploys to Workers for the dynamic routes. SSR on a Worker is the mental model; the SSR and Cloudflare bindings guide is the hands-on setup. This model is verified on Workers Static Assets; Cloudflare Pages advanced mode has not been verified for the adapter.
Local content server
A strong match when another program owns the window and zfb owns the content. zfb dev is spawned by that program on a loopback port and answers requests from its WebView. In the standard embedded-V8 build with plugins: [], no Node plugin host is spawned, so the running server needs no Node.js on the machine. Other processes write MDX into the content tree while the server runs, and content-watch HMR picks the change up without a rebuild.
CCResDoc is the proof: a Tauri host spawns the native zfb binary as a subprocess on a settings-selected loopback port, Rust generators and watchers emit MDX from the configured Claude and Codex resource directories, and the host polls a real page until the response carries the expected shell before it treats the server as ready. See Desktop deployment for the composition matrix between a spawned server and the in-process zfb-server crate.
Light interactive islands
This is a property shared by all three shapes, not a fourth one. zfb suits pages that are mostly static documents with a small number of interactive components — a search box, a counter, a modal trigger. The islands model ("use client") ships a single shared islands bundle for the project and injects it only on pages that contain island markers. A page with one island may download code for the project's other islands too; pages with no islands skip the islands script, though other client-script paths can still ship JavaScript.
Where zfb sits
zfb is one layer of a content site, not the whole of one. Reading the stack top-down:
| Layer | What lives there |
|---|---|
| Framework / site experience | Astro, Next.js, VitePress, Starlight, zudo-doc |
| Site engine | zfb — routing, SSG, SSR, islands, collections |
| Content pipeline | remark/rehype, markdown-it, zfb's own MDX pipeline |
| Parser / compiler / runtime | Rust, SWC, Rolldown, esbuild, V8 |
Astro and Next.js own the site experience — sidebars, themes, blog conventions, the finished shape of a site. zfb owns the layer below that: it is the engine a framework such as zudo-doc sits on, or that an application such as CCResDoc sits on. Pick zfb when the hard parts of your project live outside page rendering and you want the rendering layer to be small, predictable, and yours to compose. If the hard part is the site experience, a framework will get you there faster.
One technical difference is worth naming: zfb's build-time JS host is embedded V8, the same engine family as Cloudflare's workerd, while Astro and Next.js build in a full Node.js process — so for Workers-targeted deployments zfb's build host is closer to the target runtime.
When to pick something else
zfb is the wrong choice in several cases — be honest with yourself before committing.
You need SSR beyond what the Cloudflare adapter offers. SSR is a supported shape, not an afterthought, but the only adapter targets Cloudflare Workers. There is no ISR, no React Server Components, no middleware layer, and no Node, Vercel, or Deno adapter. If your request-time story needs any of those, a full SSR framework is the right tool.
You need broad multi-framework support. Astro's adapter ecosystem lets you swap between React, Vue, Svelte, Solid, and others inside the same site. zfb's client side is TSX with its own zudo-react runtime; it does not provide interop for components written for those frameworks. If your team owns components in multiple frameworks and wants them all in one site, zfb is not the right host.
You have 100 000+ pages. zfb builds an in-memory content snapshot and embeds it into the V8 host for the duration of the render pass. For hundreds or low thousands of MDX files this fits comfortably in default workerd memory. For very large corpora — tens of thousands of entries, or entries with multi-megabyte bodies — V8 RSS grows linearly with snapshot size. At that scale the snapshot design needs rethinking (see the Scaling sweet spot section below), and zfb does not solve that problem today.
You want a proven, widely-adopted tool with a large ecosystem. zfb is a focused, opinionated engine. If you need a large community, a rich plugin ecosystem, or battle-tested production scale today, Astro is the right answer.
Scaling sweet spot
The engine is designed for hundreds to low thousands of MDX pages. That covers:
A typical documentation site (50–500 pages)
A developer blog with a years-long archive (100–2000 posts)
A
zudo-doc-scale content set
At those sizes the content snapshot is small, cold-start build time is measured in seconds, and the dependency graph keeps incremental rebuilds fast regardless of total page count.
Beyond roughly 10 000 pages, the snapshot-in-memory approach becomes the bottleneck. The right answer at that scale is not to build a larger monolith — it is to shard the content into multiple zfb projects (one per section, one per locale, one per content type) and compose them at the CDN layer. That composition story is on the roadmap but is not implemented today.
To inspect the actual snapshot footprint of your build:
ZFB_DEBUG_SNAPSHOT=1 pnpm exec zfb buildThis prints a single line to stderr:
content snapshot: 187 entries / 412 KBKB here is the byte size of the deterministic JSON serialization — a reliable proxy for V8 heap cost. Watch this number as your content grows. If it climbs past a few hundred megabytes, you are approaching the edge of the sweet spot. The full explanation of the memory model lives in the README scaling note.
Where to go next
Three ways to run zfb — the static build, the Worker, and the local content server, side by side.
Getting started — scaffold your first site.
Design philosophy — the "narrow on purpose" stance and the recipes-over-plugins framing that explain why this set of trade-offs.
Architecture: Build engine — how the Rust crates, the JS host, and the snapshot fit together.
Engine vs Framework — the documented surfaces zfb provides, and what lives outside the engine.