zfb
GitHub repository

Type to search...

to open search from anywhere

Your first site

Scaffold, run, and build a zfb project in about five minutes.

The shortest workflow

With the CLI installed, select the node-free template explicitly. Stop dev with Ctrl+C before continuing.

zfb new my-site --template node-free
cd my-site
zfb dev
# Stop with Ctrl+C
zfb check --skip-tsc
zfb build
zfb preview

--skip-tsc runs only the non-TypeScript checks. For full type checking, install Node.js and TypeScript and use zfb check. The npm distribution runs these same commands through pnpm exec zfb or npx zfb.

Choose Basic blog for a package-based blog, or Node-free for a starter that runs without Node or a package install. Use either tab below to create, run, build, and preview your site after Installation.

Scaffold a new project

pnpm create zfb@latest my-site
# or
npm create zfb@latest my-site

See the output before you run it

create-zfb.takazudomodular.com serves exactly what this command produces — the basic-blog template, built and deployed straight from main on every push. Nothing about the site is hand-written: it is generated in CI by the same clean-room run that gates every pull request, so it cannot drift from the template you are about to get.

pnpm 11 note

pnpm 11's minimumReleaseAge may install a previous release of create-zfbwithin ~48h of any new release. If create-zfb warns about a stale install at startup, re-run with pnpm create zfb@latest --config.minimumReleaseAge=0or use npm create zfb@latest instead.

This runs the create-zfb initializer, which calls zfb new under the hood and copies the bundled basic-blog template into my-site/. If pnpm is on your PATH, zfb runs pnpm install automatically right after copying the template; otherwise it prints a short note telling you to run it yourself.

cd my-site

If you already have the zfb CLI installed globally (see Installation), you can invoke zfb new directly with the same result:

zfb new my-site --template basic-blog

--template basic-blog is the default, so you can omit it. A node-free template is also available for projects that need no Node.js dependency — it ships no package.json and relies on .md/.html page entries alongside .tsx; see Markdown and HTML Pages for the authoring surface it uses.

basic-blog scaffolds a zfb.config.ts (not JSON), a blog content collection with three seed posts, four routes, and one client island. Its README.md is a tour of the tree; Project structure covers the same ground in more depth.

Import specifiers

The bare zfb family — zfb, zfb/content, zfb/paginate, zfb/zudo-react, and the other supported subpaths — aliases to the matching @takazudo/zfb exports in SSR, the island scanner, client bundles, JSX pragma classification, and zudo-wind class extraction. For package-backed entries, either spelling resolves to the same package identity; these docs use the shorter zfb form. The config loader handles zfb/config by aliasing it to an internal runtime stub.

These build aliases do not configure TypeScript. zfb check is unchanged: it runs TypeScript with your project configuration and does not inject compilerOptions.paths. TypeScript and editors use the ambient declarations in components/zfb-shim.d.ts. See Typing bare zfb imports for the full shim and guidance for extending an existing one.

Start the dev server

pnpm zfb dev
# or
npx zfb dev

You'll see a "ready" banner with the host and port (defaults: http://localhost:3000). zfb watches a fixed set of project roots — pages/, content/, components/, layouts/, styles/, data/, src/, and the two config files (zfb.config.json, zfb.config.ts) — plus any additional paths declared as collection path values or absolute extraWatchPaths entries in your config. The default public/ directory is not watched; those files are served directly from disk. Saving any tracked file triggers a live-reload broadcast to connected browsers.

You can override host and port from the CLI — they always win over zfb.config.ts:

pnpm zfb dev --port 4000 --host 0.0.0.0
# or
npx zfb dev --port 4000 --host 0.0.0.0

Build and preview

To produce a static build of the site:

pnpm zfb build
pnpm zfb preview
# or
npx zfb build
npx zfb preview

zfb build writes to the directory selected by CLI --outdir → config outDir → the built-in dist/ default, then enumerates routes via the file-system router and writes one HTML file per static route. The build command has no --port flag because it does not start a server.

zfb preview uses the same output-directory precedence and serves the selected directory over HTTP. Preview's --port flag wins over config port; if neither is set, preview uses the built-in 4321 default.

All three commands honor outDir in zfb.config.*. For build and preview, an explicit --outdir always overrides the configured value.

Type-check the project

pnpm typecheck
# or
npx zfb check

zfb check does two things in one pass: it type-checks the project with TypeScript, and it validates every collection entry's frontmatter against the JSON Schema declared for that collection in zfb.config.ts. The build itself does not validate frontmatter, so this is where a post missing title or date gets caught. See CLI reference.

A working example

zfb-example-blog is a standalone example site you can read and deploy, with a live build. It is maintained as its own repository rather than as a copy of the bundled template, so its file layout differs from what zfb new scaffolds — read it as a worked example, not as a mirror of your new project. Blog walks through it in full, and Examples lists the rest.

Own the starting design

Both bundled starters begin with the Everyday design: semantic colour roles, independent horizontal and vertical spacing, readable type and one corner rule. These are editable project choices, not zudo-wind engine defaults.

  • Edit styles/design-system.css for colours, spacing, type, measure and radius.

  • Read DESIGN-NOTES.md for when to use the roles; components/design-rules.ts supplies the same short rules displayed on the home page. Update those explanations when changing the design.

  • In Basic blog, zfb.config.ts merges design-tokens.json with the existing Markdown showcase tokens. Local dark values in styles/global.css follow the theme toggle. The existing How this site is styled post explains the chain.

  • In Node-free, keep renamed tokens in zfb.config.json and design-tokens.json in sync. Its explicit Wind stylesheet builds inside the binary, with no Node, package install or client island required.

Try the Design system playground, change its rules, and export editable files. Merge token maps by category and name so existing pages keep their values. The initializer currently selects a site template; it has no design-seed selector or seed flag.

  • Project structure — what every directory the template created actually does.

  • Routing — how pages/ becomes URLs, including dynamic and catchall routes.

  • Islands — how to opt individual components into client-side hydration.

  • Build engine — how the Rust crates fit together under the hood.

Revision History

CreatedUpdated