Project Config
Customize the CLI per-project with create-turbo-stack.json
CLI config — defaults, policy, plugins, registries, conflict policy — lives in
one place per project: the config block of .turbo-stack.json. So a project
needs a single file. An out-of-project create-turbo-stack.json (walked up from
cwd) or the global ~/.create-turbo-stack/config.json is optional, for org/team
defaults shared across repos; the project's config block wins on overlap.
| Where | Owner | Purpose |
|---|---|---|
.turbo-stack.json config | You (in the project) | This project's config — the common case |
create-turbo-stack.json | You (team/external) | Org defaults shared across repos (optional) |
~/.create-turbo-stack/config.json | You (machine global) | Personal defaults (optional) |
The rest of .turbo-stack.json (resolved preset, catalog, …) is CLI-managed —
don't hand-edit it; the config block is yours to edit.
Shape
The same UserConfigSchema applies whether it's the config block of
.turbo-stack.json or a standalone create-turbo-stack.json:
{
"$schema": "https://create-turbo-stack.dev/schema/user-config.json",
"defaults": { /* ... */ },
"policy": { /* ... */ },
"plugins": ["@scope/cts-plugin"],
"registries": { "@acme": { /* ... */ } },
"conflictPolicy": "prompt"
}defaults
Pre-fill prompt initial values. Anything not set falls back to the schema default.
{
"defaults": {
"basics": {
"scope": "@acme",
"packageManager": "pnpm",
"linter": "biome",
"typescript": "strict",
"gitInit": true
},
"database": { "strategy": "drizzle" },
"api": { "strategy": "trpc" },
"auth": { "provider": "better-auth" },
"css": { "framework": "tailwind4", "ui": "shadcn" },
"integrations": {
"errorTracking": "sentry",
"envValidation": true
}
}
}policy
Three-mode constraint: allow whitelists, forbid blacklists, require locks the value entirely (no prompt).
{
"policy": {
"allow": { "auth": ["clerk", "better-auth"] },
"forbid": { "css": ["vanilla", "css-modules"] },
"require": {
"typescript": "strict",
"envValidation": true,
"packageManager": "pnpm",
"database": "drizzle"
}
}
}allow + forbid apply to the same enum at prompt time (forbid wins on overlap). require removes the prompt and forces the value — useful for compliance ("typescript strict everywhere", "we use Drizzle, period").
After a preset is fully assembled — interactive, --preset, or add/remove/switch — it's checked against policy a second time. Violations abort the operation.
plugins
npm package names whose default export contributes registry entries.
{ "plugins": ["cts-plugin-nuxt", "@acme/cts-internal"] }The CLI imports each plugin at startup and registers its default export. See Plugins.
registries
Namespaced package registries for cts add @ns/<name> (see
Registry Packages). A bare string is the URL template; the object
form adds auth headers / query params and an Ed25519 publicKey to verify
signatures. ${VAR} placeholders resolve from the environment (and the project's
.env / .env.local) at request time, so tokens never live in the file.
{
"registries": {
"@acme": {
"url": "https://store.acme.com/r/{name}",
"headers": { "Authorization": "Bearer ${ACME_TOKEN}" },
"publicKey": "<base64 SPKI>"
}
}
}conflictPolicy
How applyDiff handles files you've hand-edited since the last scaffold:
prompt (default, interactive), keep, overwrite, or abort. Set it so CI /
MCP / scripted runs don't deadlock on the prompt.
{ "conflictPolicy": "keep" }Global config
Optional. ~/.create-turbo-stack/config.json has the same shape; project values override on overlap. Useful for "always use my org's scope" preferences without committing them to every repo.
Discovery
create-turbo-stack list shows everything that's currently registered, including plugin-provided entries. Use it to confirm a plugin loaded after editing create-turbo-stack.json.