Quickstart
Go from one command to a running, signed-in app, and where to go next.
Two commands take you from nothing to a running, signed-in app.
Prerequisites
Bun is required (the repo pins bun@1.3.14 via packageManager in the root package.json). Run the CLI with bunx, not npx: it shells out to bunx to fetch the scaffold, install dependencies, provision Postgres, and migrate, streaming each step's progress. If Bun is missing it shows how to re-run under Bun (bunx --bun zerostarter ...) and offers to install it for you. Docker is optional: init uses it to provision a local Postgres automatically, and without it you set POSTGRES_URL yourself.
bunx zerostarter init
bun run devThe rest of this page is what those commands do, and the one thing to check if the database step gets skipped.
zerostarter init
bunx zerostarter init scaffolds a fresh product into the current directory, and the directory name becomes your project name. Run it in an empty folder of its own; if the folder already has files, it asks for a project name and scaffolds into that new directory instead, and it stops early if you run it inside an existing workspace or monorepo, where a parent lockfile would break the dependency install. In one run it:
- fetches the latest ZeroStarter and strips the sample content,
- rebrands the copy to your project name,
- sets your feature flags (docs, blog, API reference, internal docs, waitlist), from an interactive checklist or
--<flag>/--no-<flag>flags, - installs dependencies with Bun from the shipped
bun.lock, so the first install resolves from locked versions instead of a slow cold resolve (progress streams live), - provisions a local Postgres in Docker (via pglaunch), reusing an already-running one when you re-run
init, and applies the migrations, - writes
.envfrom.env.examplewith a freshly generatedBETTER_AUTH_SECRETandAGENT_SIGNIN_ENABLED=true, which enables the local Login (agents) sign-in out of the box.
Everything else has a working default, so the scaffold runs as-is. The feature checklist is pre-checked to the defaults (all on except the waitlist), and any feature can be flipped later in config. The database step defaults to yes when Docker is running; pass --db to provision it without the prompt.
If Docker isn't running
init skips the database and leaves POSTGRES_URL empty. Point it at any Postgres (a hosted one like Neon works) by setting POSTGRES_URL in .env, then apply the migrations once:
bun run db:migratezerostarter reinit
bunx zerostarter reinit re-scaffolds an existing git repo as a fresh ZeroStarter: it deletes every file (keeping .git and your .env* files, so your history, remote, and local secrets survive), fetches the latest ZeroStarter, rebrands to the directory name, and commits on the current branch. Use it to point an existing repo at ZeroStarter without losing its git history. It refuses a dirty tree, and rolls back to your last commit if any step fails.
zerostarter sync
bunx zerostarter sync re-baselines an existing fork on ZeroStarter's latest scaffold. A gitpick overlay updates the starter files while your content, public/marketing, branding (site.ts), package.json identity, lockfile (bun.lock), database migrations and schema (packages/db/drizzle, packages/db/src/schema), the docs config (docs.config.ts, which describes your own docs), and favicon are preserved and the files you added are untouched. It requires a clean tree and lands as a reviewable diff you commit yourself (no auto-commit); if the overlay or reconciliation fails it rolls the tree back to your last commit, while a later dependency-install failure leaves the synced files in place for you to re-run bun install.
bun run dev
Turborepo starts both apps together through portless, which serves stable named .localhost URLs off one unprivileged proxy (bunx portless list shows them; in a git worktree each host is branch-prefixed so parallel checkouts never collide):
- web (Next.js) at
http://zerostarter.localhost:1355 - api (Hono) at
http://api.zerostarter.localhost:1355, with an interactive API reference at/api/docs
PORTLESS=0 bun run dev skips the proxy for fixed ports instead (web :3000, api :4000), which is what OAuth callbacks expect (see Authentication). It is also the fallback where the OS does not resolve *.localhost to loopback server-side (macOS and most Linux do; some containers and corporate DNS setups do not); without it, the web server can't reach api.<name>.localhost to render authenticated pages and they redirect to the home page.
Sign in
A fresh scaffold has no OAuth configured yet, so the home page shows no social buttons. init already set AGENT_SIGNIN_ENABLED=true in your local .env, so the dev-only Login (agents) button is ready in the sign-in dialog: click it (or use one curl) to mint a real session locally with no OAuth round-trip, an owner the first time it creates the account. See Working with Agents for that flow.
When you're ready for real users, wire up GitHub or Google in Authentication; each button appears only once its credentials are set.
Next
- Working with Agents: sign in locally and build your first feature.
- Architecture: what you just started, and why each piece is there.
- Authentication: add OAuth, organizations, and teams.