zazzy
CLI

The generate flow

How create-saas-starter generate turns a feature selection into a working app.

create-saas-starter generate runs an end-to-end pipeline that turns your feature selection into a verified, formatted, committed standalone app. This page walks each step in order. For the flags and prompts that feed it, see Create an app.

Flags

--name=<name>                 Project name (and output directory)
--features=<features>         Comma-separated features, or 'core' for the core-only app
--shell=<name>                Dashboard shell: topnav | sidebar | vercel | stripe (default: topnav)
--package-manager=<pm>        pnpm | npm | bun | yarn (default: detected)
--database-url=<url>          Prefill the generated .env's DATABASE_URL
--yes                         Non-interactive: use flags/defaults, skip prompts
--git / --no-git              Initialize a git repository (default: on)

Resolving the template source

Before anything runs, the CLI resolves where to copy the reference app from:

  • In-repo (development): when run from a checkout of this repo, it uses the live apps/web tree directly — authoritative and always current.
  • Published: the npm package ships a bundled template.tar.gz; the CLI extracts it to a temp directory with the system tar and cleans it up afterward.

The published path checks the root package.json name is saas-starter, so a published npx run inside some unrelated project that happens to have an apps/web/ isn't mistaken for the dev tree.

The pipeline

Once it has a project name, package manager, and resolved feature selection, the generator runs:

  1. Refuse to clobber. If the target directory exists and is non-empty, generation aborts before touching anything.
  2. Copy the reference app into the target. Build artifacts (node_modules, .next, dist, …), local env files (.env, .env.local), TypeScript build-info, and the block registry (src/registry) are excluded from the copy.
  3. Prune — delete deselected features' paths, then strip @feature marker regions from every remaining file. See the prune model.
  4. Agents overlay — if the agents feature is kept, its inert .agents-template/ tooling is moved to its final paths (e.g. CLAUDE.template.mdCLAUDE.md). A deselected agents makes this a no-op.
  5. Rewrite — collapse the two-package workspace into one standalone package.json, drop pruned features' deps/scripts/env/compose services, and delete features.json, the marker lint, and the ESLint feature-boundary rule.
  6. Generated README — replace the reference README with one listing only your selected features and your package manager's setup commands.
  7. Stamp — write .saas-starter.json (features + CLI version + timestamp). See the stamp.
  8. .env — write .env from the pruned .env.example, prefilling DATABASE_URL from --database-url if given. .env is gitignored.
  9. Lockfiles — keep only the chosen package manager's lockfile; remove the others.
  10. Verify in place — the guard that never hands over a broken app.
  11. Format — a Prettier pass over the generated tree.
  12. Gitgit init and an identity-pinned initial commit (unless --no-git).

The verify step

Before the app is handed over, generate proves it actually works, in this order:

install → prisma generate → prisma format → prisma validate → next typegen → tsc --noEmit
  • prisma generate runs before the typecheck because @prisma/client ships no PrismaClient export until the client is generated — without it, tsc can't resolve the app's db layer.
  • next typegen runs before the typecheck too: any marketing-inclusive selection imports the generated content-collections module, which a fresh app lacks until Next config eval materializes it (along with typed-route declarations).

Any step failing is a loud abort: the error names the offending step, and the generated app is left on disk for inspection — never handed over as if it worked.

Identity-pinned initial commit

The initial commit is authored with a pinned name/email, so generation never fails on an unconfigured git (fresh containers, CI). You re-author from there.

When it's done

The generator prints a package-manager-correct next-steps block:

Created my-app in my-app

Next steps:
  cd my-app
  docker compose up -d          # start Postgres (and any selected services)
  pnpm prisma migrate dev       # apply the schema
  pnpm dev                      # start the app on http://localhost:3000

See First run for what each step does.

On this page