Skip to content
NestJS ns getting-started 5 min read

Installation & Setup

Getting a NestJS project running takes about a minute once your tooling is in place. The recommended path is the Nest CLI — a command-line tool that scaffolds a fully configured TypeScript project with sensible defaults, a build pipeline, and a test harness, so you write features instead of boilerplate. This page walks through the prerequisites, installing the CLI, generating a project with nest new, exploring what gets created, and verifying everything works in both development and production modes.

Prerequisites

NestJS targets modern Node.js. You need an active LTS release of Node.js (Node 18, 20, or 22 at the time of writing) and a package manager. The CLI works with npm, pnpm, and Yarn interchangeably. Verify your toolchain before starting:

node --version
npm --version

Output:

v20.11.1
10.2.4

If your Node version is older than the current LTS, install nvm and run nvm install --lts. NestJS uses recent ECMAScript and TypeScript features, and older runtimes can fail at build or startup.

Installing the Nest CLI

The CLI is published as @nestjs/cli. Installing it globally gives you the nest command everywhere, which is convenient for scaffolding new projects:

npm install -g @nestjs/cli

Confirm the install and check the version:

nest --version

Output:

11.0.0

You do not strictly need a global install — you can scaffold with npx @nestjs/cli new — but a global CLI makes day-to-day commands like nest generate shorter.

Scaffolding a project with nest new

Create a new application with the new (alias n) command. The CLI prompts you to choose a package manager, then generates the project, installs dependencies, and initializes a Git repository:

nest new my-app

Output:

⚡  We will scaffold your app in a few seconds..

? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm
  yarn
  pnpm

CREATE my-app/src/app.controller.ts (274 bytes)
CREATE my-app/src/app.service.ts (142 bytes)
CREATE my-app/src/app.module.ts (249 bytes)
CREATE my-app/src/main.ts (228 bytes)
...
✔ Installation in progress... ☕

🚀  Successfully created project my-app

To pick the package manager non-interactively, pass --package-manager (alias -p):

nest new my-app --package-manager pnpm
FlagAliasPurpose
--package-manager <pm>-pChoose npm, yarn, or pnpm without the prompt
--skip-installScaffold files but skip dependency installation
--skip-git-gDo not initialize a Git repository
--strictEnable TypeScript strict mode in tsconfig.json
--language <lang>-lGenerate a ts (default) or js project

Use --strict for new projects. It turns on strictNullChecks and related flags, catching whole classes of bugs at compile time before they reach production.

Exploring the generated structure

The starter is intentionally small. Everything lives under src/, with configuration files at the root:

my-app/
├── src/
│   ├── app.controller.ts        # A basic controller with one route
│   ├── app.controller.spec.ts   # Unit test for the controller
│   ├── app.service.ts           # A sample provider (service)
│   ├── app.module.ts            # The root module
│   └── main.ts                  # Application entry point
├── test/                        # End-to-end tests
├── nest-cli.json                # Nest CLI configuration
├── tsconfig.json                # TypeScript compiler options
├── package.json
└── eslint.config.mjs

The entry point bootstraps the application by creating an instance from the root module and listening on a port:

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

AppModule is the root of the dependency graph. It declares the controllers Nest should register and the providers its DI container should manage:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

The controller injects the service through its constructor and exposes a single GET / route:

// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

Running the application

The generated package.json ships with ready-made scripts for every stage. For day-to-day work use start:dev, which compiles the app and reloads automatically whenever you save a file:

cd my-app
npm run start:dev

Output:

[Nest] 12345  - 06/14/2026, 10:02:11 AM     LOG [NestFactory] Starting Nest application...
[Nest] 12345  - 06/14/2026, 10:02:11 AM     LOG [InstanceLoader] AppModule dependencies initialized
[Nest] 12345  - 06/14/2026, 10:02:11 AM     LOG [RoutesResolver] AppController {/}: +2ms
[Nest] 12345  - 06/14/2026, 10:02:11 AM     LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 12345  - 06/14/2026, 10:02:11 AM     LOG [NestApplication] Nest application successfully started

Verify it by hitting the default route:

curl http://localhost:3000

Output:

Hello World!

The full set of scripts covers the whole lifecycle:

ScriptCommandUse
startnpm startRun once without watch mode
start:devnpm run start:devWatch mode with hot reload for development
start:debugnpm run start:debugWatch mode with the Node inspector attached
buildnpm run buildCompile TypeScript to dist/
start:prodnpm run start:prodRun the compiled dist/main.js in production

For production you compile first, then run the JavaScript output — never ts-node in production:

npm run build
npm run start:prod

Best Practices

  • Stick to an active LTS Node.js release and pin it with an .nvmrc file so the whole team runs the same runtime.
  • Scaffold with nest new --strict to enable TypeScript strict mode from day one.
  • Use start:dev for local work and start:prod against the compiled dist/ output for deployments — never ship ts-node.
  • Commit the generated nest-cli.json and tsconfig.json; they define how the project builds and should stay in version control.
  • Read the bind port from process.env.PORT (as the starter does) so platforms can override it.
  • Run npm audit and keep @nestjs/* packages on the same major version to avoid peer-dependency mismatches.
Last updated June 14, 2026
Was this helpful?