Upgrade notes
What changed in each release and what to do when upgrading
2.1.2
Adds instructions for AI coding agents and VS Code settings, and moves Next.js projects to the November security release. Projects you already generated are not changed.
New
- VS Code settings. Add them with
--vscode..vscode/settings.jsonfixes ESLint problems on save and uses the project's TypeScript, and.vscode/extensions.jsonrecommends the extensions for your stack. See VS Code settings. - AGENTS.md for AI coding agents. Add it with
--agentsor the new "Add AGENTS.md for AI coding agents?" prompt. It tells agents such as Codex, Cursor, Copilot, and Gemini CLI how your project works: the commands for your package manager, the database workflow, where the code lives, and rules to follow, such as validating input, keeping secrets on the server, and passing type-check and lint before a task is done. It links the official docs for each library in your stack, so an agent checks them instead of guessing. ACLAUDE.mdimports it for Claude Code. It is off unless you choose it. See AI agent instructions.
Security
- New Next.js projects require Next.js 16.4.5, which fixes the vulnerabilities in the November 3 security release, including a high-severity cache disclosure. New projects already resolved it through their version range; the minimum is now raised.
- Update existing Next.js projects: run
npm install next@latest, then rebuild and redeploy. On Netlify, a project withproxy.tsalso needs the adapter update described in Netlify's notice.
Changed in generated projects
- Express and NestJS keep
.vscode/settings.jsonand.vscode/extensions.jsonin git..gitignorenow ignores the rest of.vscode/instead of the whole folder. .dockerignoreleaves outAGENTS.mdandCLAUDE.md, which the image does not need.
For contributors
- Publishing a GitHub release publishes the CLI to npm from GitHub Actions (
.github/workflows/publish.yml), through npm trusted publishing with provenance and no stored token. docker-matrix.cjspublishes PostgreSQL on port 45432. Windows reserves blocks of ports above 49152 for Hyper-V and WSL, and the old port 54329 was in one, so the database container could not start.- The matrix scripts pass each command as one string, which removes the Node.js deprecation warning about arguments passed with
shell. generate-matrix.cjschecks thatAGENTS.mdis written only when chosen and renders without leftover template tags.
2.1.1
Adds a GitHub Actions workflow, and fixes security issues and bugs. Projects you already generated are not changed.
New
- GitHub Actions CI. Add a workflow with
--cior the new "Add GitHub Actions CI?" prompt. On every push tomainand every pull request it installs dependencies with your package manager, then builds, type-checks, and lints on Node.js 24. It needs no secrets. It is off unless you choose it. See GitHub Actions CI.
Security
- New projects require patched dependencies, including Next.js 16.4.3, past the October 14 security update with its critical remote code execution fixes, and Better Auth 1.7.14. New projects already resolved these through their version ranges; the minimum versions are now raised.
- Update existing Next.js projects now: run
npm install next@latest, then rebuild and redeploy. Next.js plans another security release on November 3, 2026, so update again after that. - Update existing Better Auth projects with
npm install better-auth@latest. - The CLI itself moves to Handlebars 4.7.10 and Zod 4.6.7, which fix reported vulnerabilities.
Fixed
npm run previewworks in TanStack Start projects. It returned a 500 since the move to Nitro in 2.1.0.- Rate limiting no longer counts
/health. Frequent health checks could use up the limit and get429, which can make a host restart the app. To fix an existing project, skip/healthinapiLimiter(Express) or add@SkipThrottle()toHealthController(NestJS). - Prisma projects build without a
.envfile, for example in CI or on a host.prisma generatefailed becauseDATABASE_URLwas missing. In an existing project, changeurl: env("DATABASE_URL")tourl: process.env.DATABASE_URL ?? ""inprisma.config.ts. - The generated Prisma client is not committed. It is now in
.gitignore. In an existing project, addsrc/generated/(Express, NestJS) or/generated/(Next.js, TanStack Start), then rungit rm -r --cachedon that folder. - A project named
dbgets a valid Compose file. Its app service had the same name as the database service. The app service is now always calledapp. - An empty project name is rejected at the prompt with a clear message.
.envno longer says to copy itself to.env. That line stays in.env.example.- The README of a generated project lists rate limiting.
- Next steps remind you to start PostgreSQL when Compose does not run it.
- Declining "Create this project?" says that nothing was created.
Changed in generated projects
- Next.js projects no longer get
PORTin.env. Next.js ignored it there. UsePORT=3001 npm run devinstead. proxy.tsis only added to Next.js projects with auth. Without auth it did nothing on every request.- Express no longer logs an error for each invalid JWT, which any client could trigger. It still answers
401. - All dependencies move to their current releases within the same major version. TypeScript stays on 6 because
typescript-eslintdoes not support 7 yet, and Prisma stays on 7 because version 8 is still a release candidate and Better Auth does not support it yet.
Docs
- Corrected the Compose section of the configuration page, the TanStack Start build description in the README, and the description of
proxy.ts.
For contributors
- CI also runs on pushes to
main, because releases go straight there. - The smoke checks verify that
/healthis never rate limited.
2.1.0
Projects you already generated are not changed.
New
- Rate limiting. Express and NestJS projects can add per-IP request limits with
--rate-limitor the new "Add rate limiting?" prompt: 100 requests per 15 minutes on every route, and 10 sign-up or login attempts with auth. It is off unless you choose it. See rate limiting. - A README in every project, with the chosen stack, setup steps, scripts, and environment variables.
- Docker uses your package manager. The image installs with npm, pnpm, or bun to match the project, and uses the committed lockfile when there is one.
- A database in Docker Compose. With Prisma or Drizzle, Compose runs PostgreSQL; with Mongoose, MongoDB as a replica set. The app waits for it to be healthy. See Docker.
- Docker health checks. Images check
/health(Express and NestJS) or/(Next.js and TanStack Start). - Environment validation. Express and NestJS projects check their environment variables with Zod in
src/env.tsat startup and stop with a clear message when one is missing or malformed. CORS_ORIGIN. Express and NestJS read the allowed origins from.env. The default*allows every origin, as before.- TanStack Start runs on Nitro in production, as TanStack's hosting guide recommends for Vite.
vite buildwrites a self-contained server to.output/, andnpm startrunsnode --env-file-if-exists=.env .output/server/index.mjs.srvxis gone, and so is the Windows problem where Node.js 24 before 24.20 returned 404 for CSS and JS. The Docker image runs.output/without anode_modulesinstall.vite devis unchanged. - Graceful shutdown in Express. On
SIGTERMor Ctrl+C the server finishes open requests and closes the database connection before exiting.
Changed
- The package manager defaults to the one that ran the CLI:
pnpm dlx better-ts-stackselects pnpm, andbunxselects bun. With--yesthis is the default too;npxstill selects npm. - A folder that only holds
.gitcan be used, for example a clone of an empty repository. A failed build leaves.gitin place. - Cancelling a prompt exits with code
130instead of0. - Next steps mention
docker compose up -d dbanddocker:upwhen Docker is selected. - Home page: the docs button on the Next.js and TanStack Start home page links to the docs site, and Mongoose is listed with the other databases.
- TanStack Start projects require Node.js 24 like the others (
engineswas>=24.20.0). - Express and NestJS
JWT_SECRETmust be at least 32 characters. The generated value already is; a short value now stops the server at startup.
For contributors
ProjectConfighas auseRateLimitfield, and the newrate-limit/expressandrate-limit/nestjsmodules hold the rate-limit code.- The template matrix covers rate limiting for Express and NestJS, and the smoke checks verify the rate-limit headers and the
429after 10 login attempts.
2.0.2
Projects you already generated are not changed. To patch an existing TanStack Start project, update @tanstack/react-start to 1.168.60 or later, then rebuild and redeploy.
TanStack Start 1.0
- TanStack Start is stable. The CLI no longer labels it a release candidate.
- New TanStack Start projects require
@tanstack/react-start1.169.3 or later. This is past the fix for CVE-2026-102989, a cross-site scripting bug in server-function responses fixed in 1.168.60.@tanstack/react-router, the router devtools and SSR query packages, TanStack Query,srvx, Vite, and@vitejs/plugin-reactmove to their current releases.
Fixed
- The
cdstep is quoted when the project path has spaces, so it can be pasted as it is. - Drizzle
updatedAtcolumns update on every write. Before, they kept the creation time.
Changed in generated projects
- The Better Auth forms in Next.js and TanStack Start use
z.email()instead of the deprecatedz.string().email().
Docs
- The prompt examples in usage show the prompts as the CLI prints them since 2.0.0, and NestJS is listed wherever Express is.
2.0.1
A more useful --dry-run, bug fixes, and cleanup. Projects you already generated are not changed.
New
--dry-runlists what a build would produce. After the summary it prints every file, the dependencies and dev dependencies with their versions, dependency overrides,package.jsonscripts, environment variables, and the commands run afterwards (install,git init). Before, it only repeated the summary. Nothing is written, installed, or initialized. See dry run.
Fixed
- No terminal, no silent exit. Run without an interactive terminal and without
--yes, the CLI used to print a prompt, exit with code 0, and create nothing. It now stops with an error and a non-zero exit code. - No nested git repository. Creating a project inside an existing repository, such as
apps/apiin a monorepo, no longer runsgit init. - Express with Mongoose prints the server address when it starts, like every other project.
- TanStack Start with Drizzle pins
esbuildto 0.28.2, like the other Drizzle projects. Without it,drizzle-kitinstalled an oldesbuildthatnpm auditreports. - Project name rules in the troubleshooting page now match the CLI: lowercase letters, numbers, and hyphens.
Changed in generated projects
- Drizzle's default
DATABASE_URLispostgresql://postgres:postgres@localhost:5432/postgres, the same as Prisma's. Before it waspostgresql://user:password@localhost:5432/mydb?schema=public. - Express Prettier config no longer loads
prettier-plugin-tailwindcssor sorts React and Next.js imports first, and the package is no longer installed. - Next.js and TanStack Start auth no longer list
mongodbas a dependency unless you chose Mongoose. zodis^4.6.5in every auth module.
For contributors
- Every template file ending in
.hbsis rendered automatically. ThetemplateFileslist inconfig.jsonis gone. - The published package no longer ships type declarations or source maps, and it includes a
LICENSEfile. BuildResult.success,BuildError.exitCode, and thelowercase,uppercase, andkebabCasetemplate helpers were removed. None were used.
2.0.0
Upgrading the CLI only changes projects you generate from now on. It does not change a project you already generated.
New
- NestJS backend. NestJS 12 is a second backend framework, with the same Prisma, Drizzle, Mongoose, JWT auth, and Docker options as Express. See the backend docs.
- Flags. Every prompt has a flag, and
--yesruns the CLI without prompts.--dry-run,--help, and--versionwere added. See flags. - Project paths. The project can be created in a nested path (
apps/api) or in the current directory (.). - Request validation. Express JWT auth validates request bodies with Zod.
- New look. The CLI has a new design: a wordmark banner,
$prompts that collapse to one✓line when answered, a compact summary, and highlighted next steps. An interactive run starts on a cleared screen; runs with--yesdo not clear it.
Changed behavior
- The email must be a valid address.
POST /auth/registerandPOST /auth/loginin new Express projects return400for a malformed email. Before, any non-empty string was accepted. - A failed build cleans up after itself. If generation fails, the partial project folder is removed, so you can run the command again. A folder that already existed is emptied instead of deleted.
- The target directory is checked first. A non-empty directory is reported right after you enter the project name, not after the last prompt.
- Generated Express projects no longer include
.eslintrc.js. ESLint 10 ignored that file;eslint.config.mjsis the config in use. - Docker images for backend projects run as
appuser(wasexpressuser).
For contributors
ProjectConfig no longer has databaseType and orm. The database field (none, prisma, drizzle, or mongoose) is the only database setting. This matters if you call the builder from your own scripts.
CI runs lint, type-check, and the template matrix on Linux and Windows for every push and pull request.
Testing
npm run test:templates
node scripts/check-matrix.cjs <matrix.json> <express|nestjs|nextjs|tanstack>
node scripts/smoke-matrix.cjs <matrix.json> <express|nestjs|nextjs|tanstack>
node scripts/docker-matrix.cjs <matrix.json> <express|nestjs|nextjs|tanstack>docker-matrix.cjs needs a running Docker daemon. It builds the image of each Docker project, runs it next to a real PostgreSQL or MongoDB container, and repeats the HTTP checks.
test:templates prints the path of the matrix file to use. Pass a directory to choose where it goes: npm run test:templates -- <dir>.
1.0.8
This release requires Node.js 24 or later, for both the CLI and the projects it generates.
Upgrading the CLI only changes projects you generate from now on. It does not change the code or database of a project you already generated.
Dependency updates
Dependencies in the CLI, the docs site, and the templates were updated to their latest stable versions. The main upgrades:
| Package | Version |
|---|---|
| Next.js | 16.3.4 |
| React | 19.2.8 |
| Express | 5.2.1 |
| Prisma | 7.10.0 |
| Drizzle ORM | 0.45.2 |
| Mongoose | 9.9.5 |
| Better Auth | 1.7.3 |
| Zod | 4.5.4 |
| Tailwind CSS | 4.3.3 |
| ESLint | 10.10.0 |
Some packages are held back on purpose:
- TypeScript stays on 6.0.3. typescript-eslint 8.69.0 only supports TypeScript below 6.1, so TypeScript 7 can't be used yet.
@types/nodestays on 24.x (24.13.3), to match the minimum Node.js version.- Prisma stays on 7.10.0. Prisma 8 was still a release candidate.
Security overrides
Generated projects pin a few transitive dependencies to versions without known advisories:
- Prisma projects:
deepmerge-ts8.0.2 andmysql23.24.3 - Drizzle projects:
esbuild0.28.2
The overrides are written for npm, pnpm, and Bun. Check whether they are still needed when you upgrade Prisma or Drizzle.
Template fixes
- Express uses version 5 and its request types. The error handler takes all four parameters, and
dotenvloads before the auth modules. - Express now supports Drizzle, including JWT users stored in the database and migration scripts.
- MongoDB projects use Mongoose. The old MongoDB + Prisma option generated a PostgreSQL schema that didn't work.
- Express with Mongoose connects to MongoDB before the server starts listening. The optional user name now matches the registration API.
- Prisma generates its client before each build, and the output folders match the imports. The seed script, which pointed at a file that didn't exist, was removed.
- Better Auth 1.7.3 account tables use a unique
providerId/accountIdpair again. If your app used theissuerfield from Better Auth 1.7.0 to 1.7.2, follow the Better Auth migration guide. - The Next.js Drizzle client now receives the schema, so Better Auth can find its tables.
- Each generated project gets its own random auth secret in
.env. Set your own secrets and database URLs for production. - Express router types are explicit, so declaration output also works with pnpm.
- Express projects generated with pnpm now start correctly.
- Docker images use Node.js 24 and Compose v2, load environment variables at runtime, and stop on build errors.
Testing
Every supported combination of framework, database, auth, package manager, and Docker (90 in total) was generated. Each of the 15 distinct npm stacks was installed, built, type-checked, linted, and smoke-tested over HTTP, including sign-up, login, and protected routes against real PostgreSQL and MongoDB databases. Representative projects were also built with pnpm, Bun, and Docker.
To run the same checks from the repository root:
npm run test:templates
node scripts/check-matrix.cjs <matrix.json> express
node scripts/check-matrix.cjs <matrix.json> nextjstest:templates prints the path of the matrix file to use.
Next.js with MongoDB and Better Auth needs some database setup first. See the database docs.
Publishing (maintainers)
From the repository root:
npm ci
npm run build
npm run lint
npm run type:check
npm pack --workspace better-ts-stack --dry-run
npm login
npm publish --workspace better-ts-stack --access public --tag latestThe prepack script rebuilds the CLI, and the published package contains the compiled CLI and the templates.