New
Create a new ExpressoTS v4 project from one of the official templates.
expressots new <project-name> [options]
The command clones the expressots/templates repository at the tag matching the CLI's release (e.g. v4.0.0) via degit, pre-applies a middleware preset for application projects, runs <pm> install, and rewrites package.json#name to the project folder.
Templates
| Template | When to pick it |
|---|---|
application | Default REST/GraphQL API. AppExpress + DI container, four lifecycle hooks, controllers, middleware presets, Jest with createTestApp. |
application-with-events | Same as application plus the type-safe Event Bus example wired in (UserCreatedEvent + WelcomeEmailHandler + setupEventSystemForExpress). Selected via the --events flag or the interactive prompt. |
micro | Single-file lightweight HTTP service. micro() fluent factory in src/api.ts, no DI. Ships serverless / circuit breaker / service mesh / service client examples in examples/. Supports --target cloudflare to scaffold for Cloudflare Workers instead of Node.js. |
The fourth template,
provider, is scaffolded byexpressots create --provider, notexpressots new. Use it when you are publishing a reusable@expressots/*-style npm package.
# Application (REST/GraphQL API)
expressots new my-api -t application -p npm -s api
# Application + events example
expressots new my-api -t application -p npm -s api --events
# Micro service
expressots new my-edge -t micro -p npm
Presets
Presets only apply to the application and application-with-events templates. They pre-fill src/app.ts#configureServices with a middleware preset call so the new project starts with sensible defaults.
Preset (-s) | What it pre-applies | Extra deps installed |
|---|---|---|
api (default) | Middleware.applyPreset("api"): body parsing, security headers, CORS, compression, rate limit | compression, cors, helmet, express-rate-limit |
web | Middleware.applyPreset("web"): api plus cookies and session support | cookie-parser, express-session |
graphql | Middleware.applyPreset("graphql") plus an Apollo Server scaffold | @apollo/server, @as-integrations/express5, graphql, compression, cors, helmet |
microservice | Middleware.applyPreset("microservice"): minimal stack for service-to-service traffic | compression |
minimal | this.Middleware.parse() only: you wire everything yourself | none |
expressots new my-api -t application -p npm -s graphql
Events example flag
--events (alias -e) only applies to the Application templates. When set, the CLI uses the application-with-events template instead of application. The generated project gets a working type-safe Event Bus example:
src/events/
├── user-created.event.ts # Typed event payload
└── welcome-email.handler.ts # Class-level @OnEvent handler, auto-discovered
…and app.ts calls setupEventSystemForExpress(this.container.Container) inside configureServices(). See Event System for the full reference.
expressots new my-api -t application -p npm -s api -e
Package managers
Choices: npm, yarn, pnpm, bun. bun is unavailable on Windows for expressots new.
expressots new my-app -t application -p npm
expressots new my-app -t application -p yarn
expressots new my-app -t application -p pnpm
expressots new my-app -t application -p bun # not on Windows
Options
| Flag | Alias | Type | Description |
|---|---|---|---|
--template | -t | application | micro | Template to scaffold. |
--package-manager | -p | npm | yarn | pnpm | bun | Install backend. |
--preset | -s | api | web | graphql | microservice | minimal | Middleware preset (Application templates only). |
--events | -e | boolean | Use application-with-events (Application templates only). Pass the flag alone (-e), not -e interactive. |
--target | — | cloudflare | Deployment target (Micro template only). See Deployment targets. |
--directory | -d | string | Parent directory for the new project. |
-tand-pgo together. The CLI requires both when you use either one (yargsimplies). Example:expressots new my-api -t application -p npm. Pass neither flag to get the interactive prompts instead.
exis an alias forexpressots(same binary from@expressots/cli).
Deployment targets
By default expressots new scaffolds a project that runs on Node.js. --target swaps that for a different runtime.
| Target | Template | What changes |
|---|---|---|
cloudflare | micro only | Adds wrangler.toml with nodejs_compat and a pinned compatibility_date; swaps the npm scripts to Wrangler (dev, build, deploy, types); rewrites src/api.ts to export a Worker fetch handler; swaps Jest for Vitest with @cloudflare/vitest-pool-workers so the suite runs inside workerd; removes the Node-only files (.env.example, examples/, expressots.config.ts, tsconfig.build.json) and the @expressots/cli dependency. |
expressots new edge-api --template micro --package-manager pnpm --target cloudflare
There is no short alias — --target is spelled out.
Constraints
--targetimplies--template. Passing--targeton its own is rejected by yargs before anything is written to disk.cloudflaresupports onlymicro. Any other template fails withThe "cloudflare" target supports only the "micro" template., and it fails before the project directory is created — a rejected run leaves nothing behind.
The generated project's README and AGENTS.md document the runtime constraints that apply on Workers. See Cloudflare Workers in the Micro API guide for the runtime detail.
Interactive vs silent
Without any flags the CLI prompts for every choice:
expressots new my-api
# ? Project name › my-api
# ? Package manager › npm
# ? Template › application
# ? Middleware preset › API :: REST API with security, compression, and auto-logging.
# ? Include the type-safe Event Bus example? › No
The prompts adapt to the template you pick. Choosing Micro asks for a deployment target instead of a preset:
expressots new edge-api
# ? Project name › edge-api
# ? Package manager › pnpm
# ? Template › Micro :: A minimalistic template for building micro APIs and serverless functions.
# ? Select a deployment target › Cloudflare Workers :: Deploy to the edge with Wrangler.
Because the target prompt only appears for micro, the wizard cannot produce a combination the --target flag would reject.
With the flags above it runs silently and never blocks for input: ideal for CI scripts, template generators, or npx recipes.
Preset default: when
-sis omitted in silent mode with theapplicationtemplate, the CLI defaults to-s api(the recommended preset). This meansexpressots new my-api -t application -p npmandexpressots new my-api -t application -p npm -s apiproduce the same project.
Environment overrides
The scaffold flow reads a few environment variables aimed at contributors and pre-release testers. None of them are required for normal use.
| Variable | Effect |
|---|---|
EXPRESSOTS_TEMPLATE_REF | Override the templates ref. Set to feature/v4.0, main, a tag like v4.0.0, or any git ref. Useful for testing template changes before they ship. |
EXPRESSOTS_DEV=1 | Marks the run as a dev/contributor run. Pairs with the two flags below. |
EXPRESSOTS_USE_LOCAL_TEMPLATES=1 | Together with EXPRESSOTS_DEV=1, copies templates from a local checkout instead of cloning from GitHub. Set EXPRESSOTS_TEMPLATE_LOCAL_PATH to the absolute path of your expressots/templates checkout. |
EXPRESSOTS_SKIP_INSTALL=1 | Together with EXPRESSOTS_DEV=1, skips <pm> install. The placeholder substitution and preset file injection still run, so the resulting project is structurally complete; you just install dependencies yourself. |
For preview CLIs (-preview.x, -alpha.x, -beta.x, -rc.x), if the templates tag for that version doesn't exist on GitHub yet the CLI automatically falls back to the feature/v4.0 branch and prints a yellow warning. Pass EXPRESSOTS_TEMPLATE_REF=... to take manual control.
What happens after new
- Resolve the template ref (
v${BUNDLE_VERSION}, thenfeature/v4.0for previews, thenEXPRESSOTS_TEMPLATE_REFif set). degit expressots/templates/<template>#<ref>into the project folder.- For
application/application-with-events: inject preset deps intopackage.json, drop preset-specific files (e.g.graphql/schema.tsfor the GraphQL preset), and replace// __MIDDLEWARE_PRESET_PLACEHOLDER__insrc/app.tswith the matchingMiddleware.applyPreset(...)call. <pm> install(skipped underEXPRESSOTS_SKIP_INSTALL=1).- Rewrite
package.json#nameto the project folder name.
After it finishes
cd my-api
npm run dev
The dev server starts with tsx watch, the Studio Agent attaches on ws://localhost:3334, and the banner prints with route counts, middleware counts, and startup time.
Troubleshooting
| Problem | Fix |
|---|---|
Missing dependent arguments: template -> package-manager | You passed -t without -p (or the reverse). Add both, e.g. -t application -p npm, or drop both flags for interactive mode. |
Invalid values: package-manager, Given: "interactive" | -e is boolean only. Use -e to enable events, or omit all flags for interactive prompts. Never pass -e interactive. |
| Node.js version warning | The CLI never blocks on Node version: it only prints a warning when your version is outside the tested >=20 <=24 range and continues scaffolding. Use Node v20.x or v22.x LTS to avoid the warning. |
bun missing from choices | Expected on Windows. Use npm, yarn, or pnpm. |
degit ... permission denied / MISSING_REF | Templates tag for this CLI version is not on GitHub yet. The CLI auto-falls back to feature/v4.0 for preview builds. Override with EXPRESSOTS_TEMPLATE_REF=<branch-or-tag>. |
| Existing folder with the same name | degit refuses to overwrite. Remove or rename the folder first. |
| Need a fully offline scaffold | EXPRESSOTS_DEV=1 EXPRESSOTS_USE_LOCAL_TEMPLATES=1 EXPRESSOTS_TEMPLATE_LOCAL_PATH=<abs-path-to-templates> |
See also
generate: scaffold resources inside the new project.providers:expressots create --providerfor theprovidertemplate.running:dev/build/prod.- Bootstrap: every option
bootstrap()accepts. - Middleware: what each preset actually does.