zfb
GitHub repository

Type to search...

to open search from anywhere

CLI Reference

Complete reference for the zfb command-line interface — subcommands, flags, and environment variables.

Overview

The zfb binary exposes five subcommands for the full development lifecycle:

zfb new    — scaffold a new project from a template
zfb dev    — local development server with live reload
zfb build  — production build
zfb preview — serve a previously built site
zfb check  — typecheck and validate content-collection schemas

Run zfb --help or zfb <subcommand> --help to see the generated help text directly.

zfb new

Scaffold a new project from a built-in template.

zfb new <name> [--template <template>]

Arguments

NameTypeRequiredDescription
namepositionalyesName of the new project. Used as the destination directory.
--templatestringnoTemplate to scaffold from. Default: basic-blog.

Templates

v0 ships two templates, both baked into the binary at compile time from crates/zfb/templates/:

  • basic-blog (default) — full-featured blog scaffold with package.json; zfb new runs pnpm install for it automatically when pnpm is on PATH.

  • node-free — ships no package.json and skips the post-scaffold pnpm install step entirely, for projects run with no Node/pnpm on PATH. See Markdown and HTML Pages for the .md/.html page-authoring surface, and Install without Node for installing the zfb binary itself without Node.

Example

zfb new my-site
zfb new my-site --template basic-blog
zfb new my-site --template node-free

zfb dev

Start the local development server with live reload.

zfb dev [--port <port>] [--host [<host>]]

Flags

FlagTypeDefaultDescription
--portu163000*Port to bind the dev server to.
--hoststringlocalhost*Host interface to bind to. Bare --host (no value) is a shortcut for 0.0.0.0.

* Falls back through: CLI flag → port/host in zfb.config.json → built-in default.

Lazy rendering

The dev server defaults to lazy rendering: changed routes are marked stale and re-rendered on the first request rather than immediately on every file change. This keeps the inner loop fast for large sites.

To restore the pre-lazy behavior and re-render every affected route eagerly on each file change, set ZFB_DEV_EAGER=1.

Environment variables

VariableValuesDescription
ZFB_DEV_EAGER1Disable lazy dev rendering. Re-renders every affected route eagerly on each file change.
ZFB_LAZY_DEV_RENDER0 or 1Precise override of the lazy dev-render switch. 1 forces lazy; 0 forces eager. Takes precedence over ZFB_DEV_EAGER when both are set.
ZFB_DEV_BOOT_LAZY1Opt-in fast boot: when a valid prebuilt dist/ exists, serve it immediately and defer per-route rendering to the first request instead of rendering every route at boot. Requires lazy rendering (no-op when ZFB_DEV_EAGER is set). Warns and falls back to the eager boot render (hinting cold) when no servable dist/ exists. Off by default.
ZFB_DEV_BOOT_LAZYcoldSeedless boot-lazy: defers per-route rendering to the first request the same way, but without requiring a prebuilt dist/ at all. A route with no fallback artifact on disk serves the dev 404 page (with livereload) until its own first request — tabs left open during that window self-heal via livereload once each route resolves. A dist/ left over from an unrelated prior build is not required or checked here, but if one exists it still serves its (possibly stale) bytes ahead of the 404, same as Auto's checked seed does. Use when no dist/ exists yet; 1 would warn and fall back to the eager boot render in that case instead.
ZFB_DEV_DEFER_BUNDLE0Opt out of the boot-lazy bundle deferral (either variant): build the renderer before bind (no SSR-only 404 window) at the cost of a slower first-accept. On by default when boot-lazy is active.
ZFB_DEV_TIMING1 or trueEmit per-tick timing lines for dev-mode profiling. Off by default.

Example

# Default — binds localhost:3000
zfb dev

# Custom port
zfb dev --port 8080

# Expose to the LAN (0.0.0.0)
zfb dev --host

# Explicit host
zfb dev --host 192.168.1.10 --port 4321

zfb build

Build the project for production. Emits static HTML (and, when an adapter is configured, a server entry) to the output directory.

zfb build [--outdir <dir>] [--minify-html | --no-minify-html]
          [--strict-broken | --no-strict-broken]
          [--emit-render-artifacts | --no-emit-render-artifacts]

Flags

FlagTypeDefaultDescription
--outdirpathconfig / distOutput directory for the production build. Overrides config outDir; when both are absent, uses dist.
--minify-htmlboolean flagconfig/defaultEnable production HTML minification for this build. Overrides minifyHtml: false or an omitted config value.
--no-minify-htmlboolean flagconfig/defaultDisable production HTML minification for this build. Overrides minifyHtml: true from config or presets.
--strict-brokenboolean flagconfig/defaultFail this build (non-zero exit) when markdown link validation finds a broken link. Overrides strictBrokenLinks: false or an omitted config value. On a project with no linkValidation config at all, it force-enables link validation with its defaults rather than doing nothing.
--no-strict-brokenboolean flagconfig/defaultDo not fail this build on broken links. Overrides strictBrokenLinks: true from config or presets. Disables the top-level strict overlay only — a linkValidation block that explicitly sets failOnBroken: true stays in effect.
--emit-render-artifactsboolean flagconfig/defaultWrite a JSON render artifact under __zfb/render/ for every markdown/MDX-backed HTML route whose page renders exactly one top-level content region. Overrides emitRenderArtifacts: false or an omitted config value.
--no-emit-render-artifactsboolean flagconfig/defaultDo not write render artifacts for this build. Overrides emitRenderArtifacts: true from config or presets.

HTML minification is off by default unless minifyHtml: true is set or --minify-html is passed. It runs inside zfb's Rust post-processing pipeline and does not spawn a Node.js minifier subprocess. The first version is conservative: rendered HTML pages are candidates, source .html passthrough pages remain verbatim, and non-HTML outputs are skipped.

Strict broken-link gating is likewise off by default. --strict-broken and --no-strict-broken conflict — passing both is an error — and either one overrides the strictBrokenLinks config field, which in turn overrides the false default. Both flags affect zfb build only; zfb dev never sees the strict overlay and keeps whatever link-validation behavior your own linkValidation config gives it. See Link validation — Strict mode for the full behavior, including how this differs from resolveMarkdownLinks.onBrokenLinks.

Render-artifact export is likewise off by default. --emit-render-artifacts and --no-emit-render-artifacts conflict — passing both is an error — and either one overrides the emitRenderArtifacts config field, which in turn overrides the false default. Both flags affect zfb build only; zfb dev never writes render artifacts. See Render artifacts for the full JSON contract, the region rule, and which routes participate.

Example

zfb build
zfb build --outdir public
zfb build --minify-html
zfb build --no-minify-html
zfb build --strict-broken
zfb build --no-strict-broken
zfb build --emit-render-artifacts
zfb build --no-emit-render-artifacts

zfb preview

Serve a previously built site locally. Run zfb build first.

zfb preview [--port <port>] [--host [<host>]] [--outdir <dir>]

In static mode (no adapter, or adapter: "none"), zfb preview also runs the SAME two request-time layers zfb dev does, ahead of the plain static-file waterfall: a plugin's previewMiddleware registrations, then public/_redirects (see Static Assets — _redirects). A plugin claiming a URL always wins over a _redirects rule for that same URL.

Only GET/HEAD requests reach the _redirects matcher — mirrors real Workers Static Assets, which only ever probes the asset layer (and therefore _redirects) for those two methods. Any other method either reaches a plugin handler (which accepts every method) or 405s; a rule that would otherwise fire for GET /old-page never fires for POST /old-page.

_redirects and a custom `base`

Static preview serves whatever zfb build emitted under the selected output directory, and does not know about your project's base prefix — it has no prefix-stripping layer of its own. So _redirects rule sources are matched against the full request path, exactly as written in the file — they are never rewritten to add or strip a base prefix. zfb dev mirrors that matching shape even though its router is mounted under base. If zfb.config.ts sets base: "/pj/site/", a rule meant to redirect /pj/site/old-page must be written with the prefix included (/pj/site/old-page /pj/site/new-page 301), not as /old-page /new-page 301.

When zfb.config.json's adapter field names a supported adapter (e.g. @takazudo/zfb-adapter-cloudflare), zfb preview hands off to wrangler dev instead of zfb's own static server — the output directory selected from --outdir or config outDir then only pre-checks that the directory exists, since wrangler's own config controls what it actually serves. See SSR and Cloudflare Bindings.

Adapter preview runs a pre-flight pnpm exec wrangler --version check before handing off, treating zfb's tested baseline as the minimum supported version: an older wrangler aborts with upgrade guidance, while an equal or newer one proceeds (newer versions print an info line, or a warning on an untested major). Set ZFB_SKIP_WRANGLER_VERSION_CHECK=1 only as a temporary escape hatch (e.g. if wrangler's version output format changes).

Adapter mode: zfb serves nothing

Under adapter mode, wrangler dev serves the whole site — zfb never boots its own router, and no plugin host is spawned to check for previewMiddleware at all. _redirects still works there, but it's wrangler/Workers Static Assets honouring the file natively, not zfb's _redirects engine. A previewMiddleware registration has no wrangler equivalent and simply does not run under adapter-mode preview — if your project has plugins configured, zfb preview prints a one-time warning to that effect before handing off.

Flags

FlagTypeDefaultDescription
--portu164321*Port to bind the preview server to.
--hoststringlocalhost*Host interface to bind to. Bare --host (no value) is a shortcut for 0.0.0.0.
--outdirpathconfig / distDirectory to serve the built artifacts from. Overrides config outDir; when both are absent, uses dist.

* Falls back through: CLI flag → port/host in zfb.config.json → built-in default.

Output-directory precedence is likewise CLI --outdir → config outDir → built-in dist.

Example

zfb build && zfb preview
zfb preview --port 8080
zfb preview --host --outdir public

zfb check

Typecheck the project and validate content-collection frontmatter against their schemas.

zfb check [--skip-tsc]

This command runs two checks:

  1. TypeScript — invokes tsc --noEmit as a subprocess. Catches type errors in zfb.config.ts, collection schemas, and src/.

  2. Collection schema validation — validates every collection entry's frontmatter against the JSON Schema declared in each collection's schema field in zfb.config.json/zfb.config.ts. The build itself does not validate frontmatter, so this is the enforcement gate.

Either failure mode exits with a non-zero code.

Flags

FlagTypeDefaultDescription
--skip-tscboolfalseSkip the tsc --noEmit subprocess. Schema validation still runs. Useful when TypeScript is not installed or for schema-only CI lanes.

Example

# Full check — tsc + schema validation
zfb check

# Schema-only (skip tsc)
zfb check --skip-tsc

Tip

zfb check is the recommended way to validate content collections in CI. Wire it after zfb build to catch frontmatter violations that the build silently ignores.

Environment variables

The following environment variables affect zfb globally (not specific to one subcommand):

VariableDefaultDescription
ZFB_DEV_EAGERunsetSet to 1 to disable lazy dev rendering in zfb dev. Re-renders every affected route eagerly on each file change.
ZFB_LAZY_DEV_RENDERunsetSet to 0 or 1 for precise control over the lazy dev-render switch. Takes precedence over ZFB_DEV_EAGER when both are set.
ZFB_DEV_BOOT_LAZYunsetSet to 1 to opt in to fast dev-server boot: serve a valid prebuilt dist/ immediately and defer each route's rendering to its first request (warns and falls back to the eager boot render when no servable dist/ exists), or set to cold for the seedless variant — same deferral, no dist/ required; a route with no fallback artifact serves the dev 404 page until its own first request, though a leftover dist/ from an unrelated prior build still serves stale bytes ahead of the 404 where present. Requires lazy rendering; no-op when ZFB_DEV_EAGER is set.
ZFB_DEV_DEFER_BUNDLEunsetSet to 0 to opt out of the boot-lazy bundle deferral (either variant; build the renderer before bind instead of after the first request). On by default when boot-lazy is active.
ZFB_DEV_TIMINGunsetSet to 1 or true to print dev-mode phase timings for each file-change tick.
ZFB_PLUGIN_HOOK_TIMEOUT120 (seconds)Maximum time (in seconds) any single plugin hook reply is awaited before the plugin host is force-killed and the build fails. Precedence: pluginHookTimeoutSecs in config > this env var > 120s built-in default.
ZFB_ESBUILD_BINunsetAbsolute path to an esbuild binary. Used by the bundler, islands compiler, tests, and TypeScript config loading (zfb.config.ts) when an embedded/staged esbuild binary is unavailable or should be overridden.
ZFB_TAILWIND_BINunsetAbsolute path to a Tailwind CSS v4 binary. Overrides the embedded/staged Tailwind binary used by the CSS engine. An empty value is treated the same as unset, matching the ZFB_ESBUILD_BIN contract above.
ZFB_DEBUG_SNAPSHOTunsetSet to 1 or true to log the content snapshot's entry count and serialized byte size to stderr during zfb build, for monitoring V8 memory pressure on large sites. See Incremental Rebuild.
ZFB_SKIP_WRANGLER_VERSION_CHECKunsetSet to 1, true, or yes to bypass the zfb preview adapter-mode wrangler minimum-version gate. Intended for temporary release-engineering use.

Note

ZFB_PLUGIN_HOOK_TIMEOUT can also be set via pluginHookTimeoutSecs in defineConfig. The config field takes precedence over the environment variable.

Revision History

CreatedUpdated