Nest CLI Deep Dive
The Nest CLI (@nestjs/cli) is the command-line companion that scaffolds, builds, and runs your NestJS applications. Instead of hand-writing boilerplate for every module, controller, and service, you delegate that work to schematics that produce consistent, idiomatic code and wire it into the dependency-injection graph for you. Mastering the CLI dramatically speeds up day-to-day development and keeps a large codebase uniform across teams.
Installing the CLI
The CLI is typically installed globally so the nest command is available everywhere, though projects also pin it as a dev dependency for reproducible builds.
npm install -g @nestjs/cli
nest --version
Output:
11.0.5
You can verify the available commands at any time with nest --help, and inspect a specific command with nest generate --help.
Generating code with schematics
The nest generate command (aliased as nest g) runs schematics — code generators that create files and update surrounding code. The general form is nest g <schematic> <name>. Each schematic has a short alias to save keystrokes.
| Schematic | Alias | Generates |
|---|---|---|
module | mo | A @Module class and registers it in the parent module |
controller | co | A @Controller with a spec file |
service | s | An @Injectable provider |
resource | res | A full CRUD resource (module, controller, service, DTOs, entity) |
guard | gu | A CanActivate guard |
pipe | pi | A transformation/validation pipe |
interceptor | itc | A NestInterceptor |
For example, generating a users service nests it under a users directory and creates the corresponding test file:
nest g service users
Output:
CREATE src/users/users.service.ts (89 bytes)
CREATE src/users/users.service.spec.ts (453 bytes)
The generated provider is a ready-to-use injectable class:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {}
When you generate a controller in the same module, the CLI automatically declares it in the surrounding @Module, so you rarely edit module metadata by hand:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
Scaffolding a full CRUD resource
The resource schematic is the biggest time-saver: it prompts for a transport layer (REST, GraphQL, microservice, or WebSockets) and emits a complete, working CRUD slice including DTOs.
nest g resource products
Output:
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? Yes
CREATE src/products/products.controller.ts (957 bytes)
CREATE src/products/products.service.ts (625 bytes)
CREATE src/products/products.module.ts (267 bytes)
CREATE src/products/dto/create-product.dto.ts (33 bytes)
CREATE src/products/dto/update-product.dto.ts (181 bytes)
CREATE src/products/entities/product.entity.ts (24 bytes)
Useful generation flags
Two flags come up constantly. Use --dry-run (-d) to preview changes without touching disk, and --no-spec to skip test files.
nest g controller orders --no-spec --dry-run
Tip: Run
nest g resource <name> --dry-runbefore committing to a transport layer. The preview shows every file that would be created so you can confirm the structure before generating it for real.
Building and running the application
The CLI wraps the TypeScript compiler (and optionally webpack) so you do not invoke tsc directly.
| Command | Purpose |
|---|---|
nest build | Compile to the dist/ directory for production |
nest start | Compile and run the app once |
nest start --watch | Recompile and restart on file changes |
nest start --debug --watch | Watch mode with the Node inspector attached |
During development, watch mode is the default workflow:
nest start --watch
Output:
[Nest] 4821 - 06/14/2026, 9:12:03 AM LOG [NestFactory] Starting Nest application...
[Nest] 4821 - 06/14/2026, 9:12:03 AM LOG [InstanceLoader] AppModule dependencies initialized
[Nest] 4821 - 06/14/2026, 9:12:03 AM LOG [NestApplication] Nest application successfully started
For production, nest build compiles ahead of time and you start the plain Node process from the emitted JavaScript:
nest build
node dist/main.js
Configuring nest-cli.json
The nest-cli.json file at the project root controls how the CLI compiles and bundles your app. The most important settings live under compilerOptions.
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"webpack": false,
"assets": [
"**/*.graphql",
{ "include": "config/*.yaml", "outDir": "dist/config", "watchAssets": true }
]
}
}
| Option | Effect |
|---|---|
deleteOutDir | Wipes dist/ before each build to avoid stale artifacts |
webpack | Switches the build from tsc to webpack (enables HMR) |
assets | Copies non-TypeScript files (templates, .graphql, config) into the output |
watchAssets | Re-copies matched assets when they change in watch mode |
sourceRoot | The directory schematics treat as the source root |
The assets array is essential because the TypeScript compiler only emits .js files — any .hbs, .graphql, or .yaml files your app reads at runtime must be copied explicitly, otherwise they go missing in dist/.
Warning: Enabling
"webpack": truechanges how the build behaves and is required for Hot Module Replacement, but it can mask issues with dynamicrequirecalls. Stick with the defaulttscbuild unless you specifically need HMR.
Best Practices
- Install the CLI as a dev dependency in addition to globally so CI builds use the exact pinned version.
- Prefer
nest g resourcefor new feature slices to get consistent DTOs and CRUD wiring out of the box. - Always preview destructive or large generations with
--dry-runbefore writing files. - Enable
deleteOutDirto prevent stale compiled files from leaking into production builds. - Declare every runtime non-TS file in
assetsso templates and schemas ship indist/. - Use
nest start --debug --watchwhile debugging so you can attach the inspector without restarting manually.