CLI
The nestrs CLI scaffolds projects in two layouts — standalone
(one crate) or workspace (monorepo with
crates/features/ + apps/*). nestrs new picks the layout automatically
from the directory tree — no mode flags, no config file. Generated code follows
the same decorators as the framework repo (users/ for features,
api/ for composition apps).
Install
Section titled “Install”cargo install --locked nest-rs-clinestrs versionRequires Rust 1.95+ (edition 2024). That single install is all you need: the
first time you call nestrs run, the CLI installs the dev
toolchain it drives — just, bacon, cargo-nextest — once. Run nestrs doctor after install to check the Rust toolchain and list optional NESTRS_*
environment variables.
Layout detection
Section titled “Layout detection”nestrs new infers where you are and what to create. There is no
nestrs-cli.yaml — the workspace shape is already declared in the root
Cargo.toml (members = ["crates/*", "apps/*"]). The CLI walks up from the
current directory (or -o path) and reads that manifest.
| Where you run | Command | Result |
|---|---|---|
| Outside a nestrs workspace | nestrs new hello | Monorepo at ./hello/ + apps/hello/ on port 3000 |
| Inside a nestrs workspace | nestrs new blog | Thin app at apps/blog/ — next free port in module.rs |
| Anywhere (explicit) | nestrs new hello --standalone | Single crate at ./hello/ |
If apps/blog/ already exists, the CLI stops with app blog already exists — it does not overwrite.
Standalone vs workspace
Section titled “Standalone vs workspace”Standalone (--standalone) | Workspace (default) | |
|---|---|---|
| Layout | One crate — logic in src/ | Monorepo — crates/features/ + apps/* |
| Deps | nest-rs-* from crates.io | Same, via [workspace.dependencies] |
| Grow | Copy patterns by hand | nestrs g feature / g resource / g <transport>, nestrs new <app> |
| When | One binary, no shared product crate | Several apps sharing features |
Create a project
Section titled “Create a project”nestrs new hellocd hellonestrs run dev helloOpen http://localhost:3000/ — Hello World. Logic in
crates/features/src/hello/; apps/hello/ composes modules only.
Directoryhello/
- Cargo.toml
- Justfile
- README.md
Directorycrates/
Directoryfeatures/
Directorysrc/
Directoryhello/
- http/…
- service.rs
- lib.rs
Directoryapps/
Directoryhello/
Directorysrc/
- lib.rs
- main.rs
- module.rs
- tests/e2e.rs
Grow the workspace (from the workspace root or any sub-folder):
nestrs new blognestrs g resource postsnestrs new hello --standalonecd hellonestrs run devOpen http://localhost:3000/ — Hello World. Service and controller live
in src/ (no features crate).
Directoryhello/
- Cargo.toml
- Dockerfile
- Justfile
Directorysrc/
- controller.rs
- service.rs
- module.rs
- main.rs
- tests/e2e.rs
Optional Dockerfile ships in standalone mode only.
rust-toolchain.toml pins Rust 1.95 in both modes.
Templates — --template applies to new monorepos and standalone crates only.
Every workspace app uses the same thin shell; the CLI scans existing
apps/*/src/module.rs files and pins the next HTTP port in code (same pattern
as auth → 3001, api → 3002, …).
| What | Default | Override |
|---|---|---|
| New monorepo | hello — feature + apps/hello/ on port 3000 | --template empty |
| New workspace app | thin shell + auto port in HttpConfig | (no template flag) |
| Standalone crate | hello | --template empty |
Workspace .env files do not set NESTRS_HTTP__PORT — ports live in each
app’s module.rs:
HttpModule::for_root(HttpConfig { port: 3002, ..Default::default() })Optional: --check runs cargo check after generation.
Add an app to an existing workspace
Section titled “Add an app to an existing workspace”From the workspace root (or apps/, crates/features/, …):
nestrs new blognestrs run dev blogCreates a thin app under apps/blog/ (composition root only — no
service.rs / controller.rs in the app crate).
Running tasks
Section titled “Running tasks”Every project task runs through nestrs run <recipe> — the single front
door. It forwards the recipe and its arguments verbatim to
just, which reads the Justfile the
scaffolder wrote:
nestrs run dev # watch mode (rebuild + restart on save)nestrs run test unit # unit + integrationnestrs run db up # apply migrationsnestrs run # list the available recipesThe recipes are yours to edit. Add your own to the Justfile and they run the
same way — nestrs run deploy, nestrs run docker-up, whatever you write. The
framework owns the recipes it ships; you own the rest.
The first nestrs run installs the toolchain it drives (just, bacon,
cargo-nextest) once. On CI, where you provision tools yourself, set
NESTRS_NO_BOOTSTRAP=1 or pass --no-bootstrap — a missing tool then fails
with the manual install command instead of fetching anything.
Release binaries land in target/release/. nestrs run start compiles and
starts the server; use nestrs run build when you only need the artifact
(Docker, CI, or copying the binary elsewhere).
nestrs run build # default app (hello)nestrs run build blog # after nestrs new blognestrs run build --all # every app in the workspacenestrs run start hello # build + run in releasenestrs run build # target/release/hellonestrs run start # build + run in releaseThe standalone Dockerfile runs cargo build --release in a
multi-stage image — same output path as nestrs run build.
Generate features and adapters
Section titled “Generate features and adapters”Monorepo only. Generators scaffold under crates/features/src/<name>/, register
pub mod … in crates/features/src/lib.rs, and — when you run them from inside
an app — wire the edge module into that app’s module.rs. Every command takes
--dry-run (print what would change, write nothing) and a -p path
override (default: auto-discover from the current directory). Re-running a
generator is safe: it refuses to overwrite an existing feature or adapter, and
the wiring edits are idempotent.
A port is the transport-agnostic core (service + module). An adapter bolts one transport onto a port. A resource is a DB-backed CRUD port plus its HTTP adapter in one shot.
# Port only (service + module, no transport)nestrs g feature posts
# DB-backed CRUD: #[expose] entity + CrudService + HTTP adapter, deps auto-addednestrs g resource posts
# Bolt a transport onto an existing portnestrs g http posts # controllernestrs g graphql posts # resolvernestrs g ws posts # gatewaynestrs g queue posts # processornestrs g schedule posts # scheduled tasksnestrs g mcp posts # MCP toolEach adapter delegates to the port’s service, so a freshly-generated port plus
any adapter compiles immediately — the handler is the seam you fill in. The
generator prints the import line and the app-level module each transport needs
(HttpModule, GraphqlModule, ScheduleModule, …).
When the cursor isn’t inside an app, wire the edge module by hand:
use features::posts::PostsHttpModule;
#[module(imports = [ // … PostsHttpModule,])]pub struct ApiModule;g resource emits a self-contained, unauthenticated slice so it compiles in any
workspace. For auth-protected CRUD, copy the #[crud] + guard wiring from
orgs/
or users/
and import the matching Authz<Transport>Module.
Doctor
Section titled “Doctor”nestrs doctorChecks:
rustc≥ 1.95 andcargoonPATH- whether the current directory sits inside a nestrs workspace
- optional env vars (
NESTRS_DATABASE__URL,NESTRS_QUEUE__URL, …)
Use it after install and before running DB- or Redis-backed apps.
Version, about, and update
Section titled “Version, about, and update”nestrs version# → NestRS 0.1.0
nestrs about# → version, tagline, docs, repository, license, author
nestrs update# → checks crates.io; skips when already on the latest version
nestrs update --force# → cargo install --force nest-rs-cli (reinstall even at the same version)Contributors inside the monorepo clone:
nestrs update --from-path# → cargo install --locked --path crates/nest-rs-cli --forceCommand reference
Section titled “Command reference”| Command | Description |
|---|---|
nestrs new <name> | Monorepo at ./<name>/, or app at apps/<name>/ when already inside one |
nestrs new <name> --standalone | Single crate in ./<name>/ |
nestrs new <name> --template hello | Force Hello World scaffold |
nestrs new <name> --template empty | Force HTTP-only shell (no routes) |
nestrs new <name> --check | Run cargo check after scaffolding |
nestrs doctor | Toolchain and env sanity check |
nestrs version | Print the CLI version |
nestrs about | Print project metadata |
nestrs update | Install latest CLI from crates.io when a newer version exists |
nestrs update --force | Reinstall from crates.io even when already on the latest version |
nestrs update --from-path | Reinstall from monorepo crates/nest-rs-cli |
nestrs g feature <name> | Transport-agnostic port in crates/features/src/ |
nestrs g resource <name> | DB-backed CRUD port + HTTP adapter (deps auto-added) |
nestrs g http|graphql|ws|queue|schedule|mcp <name> | Add one transport adapter to a port |
Every generator accepts --dry-run and -p <path>.
Aliases: nestrs g = nestrs generate.
What’s next
Section titled “What’s next”Planned generators (see Roadmap):
migration scaffold and nestrs info (route/module scan).
- Getting started — first run after
nestrs new - Tutorial — build
postsinapps/blog/(HTTP only) - Fundamentals / Modules — how root modules compose features