Installation, Nest CLI & Project Structure
Install the Nest CLI, create and run your first NestJS project, understand every generated file, and use the CLI to generate new code.
On this page 13 sections
Introduction
The fastest and most reliable way to start a NestJS project is the official Nest CLI. It creates a complete, working project with TypeScript, a test setup and sensible defaults already configured — and it keeps generating correctly structured code for you as the project grows.
- What you need installed before starting.
- How to install the Nest CLI and create a new project.
- What every generated file does.
- How to run the app in development (watch) mode.
- How to generate modules, controllers, services and full CRUD resources.
Prerequisites
You need Node.js installed — use a current LTS release (NestJS 12, the current major version, requires Node.js 20 or newer). npm comes bundled with Node.js. Check both from your terminal:
node -vnpm -vClick Run to see what this code prints.
You will also want a code editor with good TypeScript support — Visual Studio Code is the most common choice — and an API client such as Postman, Insomnia or the VS Code REST Client extension for testing endpoints later.
Installing the Nest CLI
Install the CLI globally with npm so the nest command is available everywhere:
npm install -g @nestjs/clinest --versionIf you prefer not to install packages globally, you can run the CLI on demand with npx: npx @nestjs/cli new my-app.
Creating Your First Project
nest new my-first-apiThe CLI asks which package manager you want (npm, yarn or pnpm), then creates the folder, writes the starter files and installs all dependencies. When it finishes, move into the project:
cd my-first-apiProject Structure Explained
my-first-api/├── src/│ ├── app.controller.spec.ts # unit test for the controller│ ├── app.controller.ts # a basic controller with one route│ ├── app.module.ts # the root module│ ├── app.service.ts # a basic service (provider)│ └── main.ts # entry point — creates and starts the app├── test/│ └── app.e2e-spec.ts # end-to-end test├── nest-cli.json # Nest CLI settings├── package.json # dependencies and npm scripts ("type": "module")├── tsconfig.json # TypeScript compiler settings├── tsconfig.build.json├── vitest.config.ts # Vitest config for unit tests└── vitest.config.e2e.ts # Vitest config for e2e testsProjects created with NestJS 12 are native ES modules ("type": "module" in package.json). Two things follow from that, and you will see both in every example in this course: relative imports end in .js even though the file on disk is .ts (import { AppService } from './app.service.js') — TypeScript maps it to the right file — and main.ts can use top-level await. If you are working on an older NestJS 10/11 project, leave the .js extensions off.
The root module ties the starter controller and service together:
// src/app.module.tsimport { Module } from '@nestjs/common';import { AppController } from './app.controller.js';import { AppService } from './app.service.js';
@Module({ imports: [], controllers: [AppController], providers: [AppService],})export class AppModule {}// src/app.controller.tsimport { Controller, Get } from '@nestjs/common';import { AppService } from './app.service.js';
@Controller()export class AppController { constructor(private readonly appService: AppService) {}
@Get() getHello(): string { return this.appService.getHello(); }}// src/app.service.tsimport { Injectable } from '@nestjs/common';
@Injectable()export class AppService { getHello(): string { return 'Hello World!'; }}The Entry Point: main.ts
// src/main.tsimport { NestFactory } from '@nestjs/core';import { AppModule } from './app.module.js';
async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(process.env.PORT ?? 3000);}await bootstrap();NestFactory.create() reads your root module, discovers every controller and provider it (and its imported modules) declares, builds the dependency injection container, and returns an application instance. app.listen() then starts the HTTP server — on the PORT environment variable if set, otherwise port 3000. The last line uses top-level await, so a startup error stops the process with a clear message instead of being silently ignored.
Running the App
npm run start:devstart:dev runs the app in watch mode — every time you save a file, Nest recompiles and restarts automatically. Open http://localhost:3000 in your browser:
Click Run to see what this code prints.
| Script | What It Does |
|---|---|
| npm run start | Compiles and runs the app once. |
| npm run start:dev | Runs in watch mode — restarts on every file change (use this while developing). |
| npm run start:debug | Watch mode with the Node.js debugger attached. |
| npm run build | Compiles TypeScript into JavaScript inside the dist/ folder. |
| npm run start:prod | Runs the compiled app from dist/ (used in production). |
| npm run test | Runs unit tests with Vitest. |
| npm run test:e2e | Runs end-to-end tests from the test/ folder. |
Generating Code with the CLI
Instead of creating files by hand, use nest generate (short form: nest g). The CLI creates the file, a matching test file, and automatically registers the new class in the right module.
nest g module users # src/users/users.module.tsnest g controller users # src/users/users.controller.ts (+ spec)nest g service users # src/users/users.service.ts (+ spec)nest g resource products # a complete CRUD feature in one commandnest g resource is especially useful: it asks which transport layer you want (REST API, GraphQL, microservice or WebSockets) and whether to generate CRUD entry points, then creates a module, controller, service, DTOs and an entity class in one go.
Add --dry-run (or -d) to any generate command to see which files would be created or updated without actually writing anything.
Common Mistakes
- Using an outdated Node.js version — check node -v first if installation or startup fails with odd syntax errors.
- Running npm run start during development and wondering why changes do not appear — use start:dev for watch mode.
- Creating controllers and services by hand and forgetting to register them in a module — Nest will not know they exist.
- Deleting the generated .spec.ts files immediately — they are the starting point for the testing you will do in lesson 13.
Best Practices
- Always generate building blocks with the CLI so naming and module registration stay consistent.
- Organize code by feature folder (src/users, src/products), which is exactly what the CLI does by default.
- Keep main.ts small — it should only create the app, apply global settings and start listening.
- Commit the project to Git right after nest new, so you have a clean baseline to compare against.
Frequently Asked Questions
Set the PORT environment variable (for example PORT=4000 npm run start:dev), or change the fallback value in main.ts. Lesson 11 shows how to manage this properly with @nestjs/config.
Yes. nest new asks which package manager to use, and everything in this course works the same with any of them.
npm run build compiles everything into the dist/ folder; npm run start:prod runs node dist/main.
Key Takeaways
- Install the CLI with npm install -g @nestjs/cli and create projects with nest new.
- main.ts bootstraps the app with NestFactory.create(AppModule) and app.listen().
- app.module.ts is the root module that ties controllers and providers together.
- npm run start:dev runs the app in watch mode on http://localhost:3000.
- nest g module/controller/service/resource generates correctly registered code.
Summary
You installed the Nest CLI, created and ran your first project, and walked through every generated file. You also learned how to generate new building blocks with the CLI. Next, you will dig into modules — the organizational backbone of every Nest application.