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/webtree 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 systemtarand 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:
- Refuse to clobber. If the target directory exists and is non-empty, generation aborts before touching anything.
- 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. - Prune — delete deselected features' paths, then strip
@featuremarker regions from every remaining file. See the prune model. - Agents overlay — if the
agentsfeature is kept, its inert.agents-template/tooling is moved to its final paths (e.g.CLAUDE.template.md→CLAUDE.md). A deselectedagentsmakes this a no-op. - Rewrite — collapse the two-package workspace into one standalone
package.json, drop pruned features' deps/scripts/env/compose services, and deletefeatures.json, the marker lint, and the ESLint feature-boundary rule. - Generated README — replace the reference README with one listing only your selected features and your package manager's setup commands.
- Stamp — write
.saas-starter.json(features + CLI version + timestamp). See the stamp. .env— write.envfrom the pruned.env.example, prefillingDATABASE_URLfrom--database-urlif given..envis gitignored.- Lockfiles — keep only the chosen package manager's lockfile; remove the others.
- Verify in place — the guard that never hands over a broken app.
- Format — a Prettier pass over the generated tree.
- Git —
git initand 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 --noEmitprisma generateruns before the typecheck because@prisma/clientships noPrismaClientexport until the client is generated — without it,tsccan't resolve the app's db layer.next typegenruns before the typecheck too: any marketing-inclusive selection imports the generatedcontent-collectionsmodule, 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:3000See First run for what each step does.