// docs
THE GUIDE.
Quick start
npx create-devstack-app my-app
npm create devstack-app, pnpm create devstack-app, yarn create devstack-app and
bun create devstack-app do the same.
The wizard checks your machine (Node.js, package managers, git identity), then asks only the questions that apply to your answers so far. Nothing is written until the review screen. When it finishes, the CLI prints the next commands for your package manager, the environment variables to fill in, and any warnings (for example, CORS left open to every origin).
Requires Node.js 22.12 or newer. Generated projects target Node.js 24, on npm, pnpm, yarn or bun.
Features
- An API that is production-shaped from the first commit. Express 5, Fastify 5 or NestJS 12,
ESM or CommonJS, built around
createApp(deps)so tests need no open port:- environment validated with Zod at startup, every missing or invalid variable listed at once;
- JSON logs with a request id per request (pino, Winston, or plain JSON lines);
- one response envelope,
{ success: true, data, meta? }and{ success: false, error: { code, message, requestId, details? } }, with no stack traces; GET /health(liveness) andGET /ready(503 with per-check status while a dependency is down);- graceful shutdown:
SIGTERM/SIGINTfinish in-flight requests, close the database, exit 0.
- Fullstack in a monorepo. pnpm, npm, yarn or bun workspaces with Turborepo: the API in
apps/api, a Next.js 16 or React 19 + Vite web app inapps/web, an optional Next.js admin app, andpackages/sharedwith the response types and a typed client. In development the web apps reach the API through a/apiproxy, so there is no CORS to configure. - Data, wired in. PostgreSQL 18, MySQL 8.4, SQLite or MongoDB 8, through Prisma 7, Drizzle or
Mongoose; Redis for caching, rate limits and sessions. The database is part of
/readyand of shutdown, hasdb:*scripts, and gets a compose service when you choose Docker. - Auth that works end to end (Express, Fastify or NestJS, with Prisma + PostgreSQL):
- JWT: register, login, refresh and logout, argon2id hashes, a 15-minute access token and a rotating 7-day refresh token in httpOnly cookies; a reused refresh token ends every session;
- or Better Auth: email + password, optional GitHub and Google sign-in, database sessions and admin roles;
- optionally sessions in Redis instead of JWT access tokens;
- login, register and account pages in the web apps, and
requireAuth/requireRole('ADMIN')for your routes.
- Security you choose, imported explicitly. Helmet, CORS, origin checks, request logging,
compression, and rate limiting (fixed window, sliding window, token bucket or leaky bucket,
with
RateLimit-*headers). A missing middleware is a compile error, never a silent no-op. - The rest of a real project. Vitest or Jest with Supertest; OpenAPI at
/openapi.jsonwith a Scalar reference at/docs;/v1API versioning; ESLint 10, Prettier, Husky + lint-staged + commitlint; multi-stage, non-root Dockerfiles and a compose file for the whole stack; a GitHub Actions workflow; VS Code settings; Dependabot and issue templates;AGENTS.mdandCLAUDE.md. - Folders for the architecture you pick. Feature-scoped, clean, MVC or flat for the API; feature-based, layer-based or atomic design for the web apps.
- A Todo app to start from (optional, Express + Prisma): CRUD with filters and cursor pagination, from the Prisma model to a page in the web app, per user when you pick auth.
- Changes later without a rewrite.
addandremovemodules in an existing project; files you edited are never overwritten. - For AI assistants too.
create-devstack-app mcpserves DevStack over MCP, so an assistant can list modules, validate a stack, plan and generate it.
55 modules in all; each one has a page on the website.
Commands
create-devstack-app my-app # interactive wizard
create-devstack-app my-app --preset backend --yes # a preset, no questions
create-devstack-app my-app --config stack.json # from a stack config
create-devstack-app . --in-place # into the current directory
create-devstack-app my-app --dry-run # show the plan, write nothing
create-devstack-app my-app --preset backend --print-plan json
create-devstack-app plan --preset backend # what init would write and run
create-devstack-app modules list # every module, by category
create-devstack-app doctor # Node.js, package managers, git, Docker; in a
# project, dependencies that differ from the catalog
create-devstack-app add security-rate-limit # in a project: add modules later
create-devstack-app remove cache-redis # in a project: remove them again
create-devstack-app config set settings.license MIT # remember a default
create-devstack-app presets save team-api # keep this project's stack as a preset
create-devstack-app mcp # serve DevStack to AI assistants
Installed globally (npm install -g create-devstack-app), the CLI also answers to devstack:
devstack add security-rate-limit, devstack doctor, devstack mcp.
Built-in presets: backend, backend-fastify, backend-nest, api-mongo,
fullstack-next-express and fullstack-vite-express; presets list shows them with yours.
On the review screen you can generate, change any answer, save the stack as a preset, remember your answers as defaults, or cancel. If installing fails after the files are written, they stay: the summary says "Not verified" and lists the commands to run again. After the files are written it asks whether to make the initial git commit, and only then whether to push it to an existing, empty GitHub repository.
plan, modules, doctor, add, remove, config, presets and mcp are commands, so a
project with one of those names needs the explicit form: create-devstack-app init doctor.
| Flag | Effect |
|---|---|
--preset <name> | Start from a preset, built in or your own (presets list); you still see the review screen unless you pass --yes |
--modules <ids> | The stack as module ids, comma-separated (the website's builder writes this command) |
--option <module.key=value> | A module option, repeatable, e.g. security-rate-limit.limit=500 |
--pm <name> | Package manager: npm, pnpm, yarn or bun (default: how you ran the CLI, then a lockfile here, then npm) |
--depth <level> | wired (default): integration code included. bare: config, tooling and folders only |
--module-system <system> | esm (default) or cjs: how the API's code is loaded. Web apps stay ESM |
--config <file> | Generate from a stack config, e.g. another project's .devstack/stack.json |
--yes | Accept defaults, never ask. Never overwrites existing files |
--force | Overwrite existing files. Originals are backed up first |
--advanced | Pick modules one by one; the review screen offers fixes when they do not fit together |
--in-place | Generate into the current directory |
--dry-run | Print the plan (files and commands) and stop |
--print-plan [text|json] | Print the plan in a format; json never prompts |
--skip-install | Do not install dependencies |
--skip-git | Do not initialise git or install hooks |
--skip-verify | Skip the checks and boot test after install (the project is "Not verified") |
--github <url> | Push the initial commit to this existing, empty GitHub repository |
--start | Start the database and the dev servers when the project is ready |
--verbose | Debug output and full error details |
Exit codes: 0 success, 1 generation failed after writing (the message lists what was written),
2 invalid input or stack (nothing written), 3 cancelled.
Stack config
{
"version": 1,
"name": "acme-api",
"packageManager": "pnpm",
"modules": [
"framework-express",
"orm-prisma",
"security-helmet",
{ "id": "security-rate-limit", "options": { "limit": 500 } }
]
}
A module entry can be an id or { "id", "options" }; options are validated against the
module's schema, and defaults fill in the rest (rate limiting: windowMs, limit). The JSON
Schema for this file is published at
/schema/stack.json.
A config can also carry settings, recorded with every project:
"settings": {
"style": { "semi": true, "singleQuote": false, "tabWidth": 4, "printWidth": 100 },
"strictness": "strictest",
"moduleSystem": "cjs",
"apps": { "backend": "server", "frontend": "site" },
"ports": { "backend": 4000 },
"license": "MIT",
"author": "Ada Lovelace",
"initialCommit": true
}
The code style goes into .prettierrc and every generated file follows it; strictest adds
noUncheckedIndexedAccess, exactOptionalPropertyTypes and noImplicitOverride;
moduleSystem: "cjs" makes the API CommonJS (the source stays TypeScript); apps and
ports rename the monorepo's apps everywhere (folders, compose, Dockerfiles, env).
Every generated project records its own config in .devstack/stack.json; passing it to
--config regenerates the same files.
Change a project later: add and remove
Run in a generated project's root folder:
create-devstack-app add cache-redis --dry-run # list the changes first
create-devstack-app add cache-redis # write them, then install
create-devstack-app remove cache-redis
DevStack compares what it generated, what the stack needs now, and what is on disk. Files you
have not touched are updated, created or (on remove) deleted. A file you edited is never
overwritten: the new version is written next to it as <file>.devstack-new for you to merge,
or --force overwrites it after a backup. package.json and pnpm-workspace.yaml are merged
and new variables are appended to .env. remove refuses a module another one still needs.
Remembered defaults and your presets
create-devstack-app config set packageManager pnpm
create-devstack-app config set settings.style.semi true
create-devstack-app config list # also: get, unset, path
create-devstack-app presets save team-api --description "Team API"
create-devstack-app presets list # also: show, delete
Defaults live in ~/.config/devstack/config.json (or $XDG_CONFIG_HOME/devstack): the wizard
pre-selects them and --yes uses them. "Remember as my defaults" on the review screen saves
your answers. Flags win over a --config file, which wins over a preset, which wins over your
defaults. Presets are saved in ~/.config/devstack/presets/ and work with --preset <name>.
Use from AI assistants (MCP)
create-devstack-app mcp is a local MCP server over stdio: your AI assistant starts it, no
hosting involved. It offers list_modules, list_presets, validate, plan, init,
add_modules and remove_modules. Add it to Claude Code with
claude mcp add devstack -- npx create-devstack-app mcp, or to any client's config:
{ "mcpServers": { "devstack": { "command": "npx", "args": ["create-devstack-app", "mcp"] } } }
init only writes into a new or empty folder given as an absolute path, and the add and
remove tools keep the same rules as the commands.
Safety
- Nothing is written until the whole plan has rendered. Files are staged in a temp directory, then copied in.
--yesnever overwrites. With--forceor an interactive "overwrite", originals are copied to a backup directory first and the summary says where.initnever deletes anything;removedeletes only files it generated that you have not changed, after backing them up.- Symlinks, non-regular files and paths outside the project are refused before anything is written.
- Project names follow npm's rules, including reserved and Windows device names.
- Commands run without a shell, and the package runs no install scripts.
- Every release is built and published by GitHub Actions from a tagged commit, with npm
provenance; check it with
npm audit signaturesin a project that depends on the package. Third-party code bundled into the CLI is listed with its licences indist/THIRD_PARTY_NOTICES.md.