Eject
Permanently sever every GenerateSaaS tie - the heartbeat cron, the manifest, the internal license route, and the update tooling - leaving your application code untouched.
generatesaas eject is the permanent, supported opt-out from the license heartbeat. It deletes the CLI's connective tissue so the project becomes fully standalone; your application code and @repo/config flags keep working unchanged.
This is irreversible and requires typing eject to confirm. Commit first so the diff is reviewable, and note that you lose generatesaas update for good.
What it removes
Run it from the project root; it aborts if .generatesaas/manifest.json is missing.
| Target | Action |
|---|---|
packages/api/src/functions/maintenance/license-heartbeat.ts | Deleted - the daily heartbeat cron |
packages/api/src/lib/cron-spread.ts | Deleted - the heartbeat's cron spreader |
packages/api/src/lib/manifest.ts | Deleted - the build-time manifest reader |
packages/api/src/routes/internal/license.ts | Deleted - the internal /license route |
packages/api/tests/functions/license-heartbeat.test.ts | Deleted - the heartbeat's own suite |
packages/api/tests/lib/cron-spread.test.ts | Deleted - the cron spreader's own suite |
.generatesaas/ | Deleted - manifest dir (license token, version) |
| Bundled skill dirs | Deleted - the shipped generatesaas-update and generatesaas-translate skills in every AI-tool root |
packages/api/src/routes/inngest.ts | Modified - strips the heartbeat import + registration |
packages/api/src/routes/internal/index.ts | Modified - strips the license route import + .route() |
packages/api/src/routes/public/v1/health.ts | Modified - drops the manifest version from the health response |
.gitignore | Modified - removes .generatesaas entries |
Shipped skill dirs are removed from every AI-tool root (.claude, .cursor, .agents, .gemini, .windsurf); skills you authored yourself in those roots are kept. Each delete is no-op-safe: missing targets are skipped, not errored.
How it runs
.generatesaas/manifest.json; cancels with a non-zero exit if absent or unparseable.eject exactly; anything else (or Ctrl+C) cancels.event: "eject"), so a legitimately ejected project stays distinguishable from an unlicensed copy. Best-effort - ejecting works offline, and nothing is ever sent again..generatesaas/..gitignore.If a file cannot be auto-modified because its lines shifted, eject logs a warning naming it so you can remove the references by hand - it never fails silently.
What survives, what is lost
| Survives | Lost |
|---|---|
| All product code, pages, components | The daily heartbeat cron |
Every @repo/config flag and the features it gates | The dormant license layer (/license route, manifest reader) |
| Database, billing, auth, every backend package | generatesaas update - no more CLI-delivered version diffs |
Common questions
| Question | Answer |
|---|---|
| Can I undo an eject? | No. The deletions are real filesystem changes with no restore path. Recovery means git revert or git checkout of the commit, which is why you commit first. |
| Will my app break afterwards? | No. The removed files are GenerateSaaS infrastructure, not application logic, and the manifest reader already goes dormant when the token is empty. |
| Do I have to eject to stop the heartbeat? | Only if you want it gone permanently. The heartbeat validates your install and sends no application or user data - eject is the clean removal, not a workaround. |