Stamp & versioning
The .saas-starter.json stamp and the exact-version policy for blocks.
A generated app deletes features.json, so it keeps no record of which features
it was built with or which CLI produced it. The stamp — .saas-starter.json
at the app root — is that record, and it's what makes add
safe.
The stamp
generate writes .saas-starter.json after the rewrites (so Prettier formats it
and the initial commit captures it):
{
"templateVersion": "1.2.3",
"features": ["auth", "billing", "email", "jobs", "orgs"],
"generatedAt": "2026-07-18T00:00:00.000Z"
}templateVersion— the CLI package version that generated the app. This is the versionaddmust match.features— the full resolved selection, core included, alphabetically sorted.addreads this to enforce each block'srequires.generatedAt— an ISO timestamp of generation (informational).
The file is validated with a strict schema when read; unknown fields are rejected.
Why add requires an exact version match
A block's source is only ever CI-proven against its own template snapshot.
The reference app evolves — a component's props change, a feature's surface
shifts — so a block written for create-saas-starter@1.2.3 isn't guaranteed to
compile against an app generated by @1.3.0. Rather than install something that
might silently break, add refuses on any mismatch and tells you the exact CLI
to use:
This app was generated by create-saas-starter@1.2.3, but you are running @1.3.0.
Blocks are written against an exact template version. Install with the matching CLI:
npx create-saas-starter@1.2.3 add upgrade-cardPinning the CLI to the app's stamped version guarantees the block you install is the block that was tested against your app's exact template.
Development versions
A checkout of this repo carries version 0.0.0. An app generated from that
checkout is stamped 0.0.0 too, and the dev CLI is 0.0.0, so they match — local
development and testing work without special-casing.
Apps generated before the registry existed
If you have an app from before the stamp was introduced, add will tell you it's
missing and how to hand-author one:
{
"templateVersion": "<your CLI version>",
"features": ["auth", "orgs", "..."],
"generatedAt": "<ISO date>"
}Place it at the app root as .saas-starter.json with the version you generated
with and your actual feature set.
The stamp is the app's identity
Two things the add command can't recover any other way live here: which
features the app has (for requires checks) and which template it was built
against (for the version match). Keep it committed.