Skip to main content

First Steps with NestJS

NestJS organizes backend applications using a modular structure inspired by enterprise patterns. In this practical guide, you will learn how to install the CLI, instantiate a new project, understand its internal architecture, and build your own modules, controllers, and services.


1. Architecture and Component Foundations

Before writing code or generating files with the CLI, it is essential to understand how key components interact within a NestJS module:

Main Component Breakdown:

  • Module (@Module): The fundamental organizational unit in NestJS. It groups related controllers and providers (services), defining dependency boundaries and enabling a scalable modular architecture.
  • Controller (@Controller): Responsible for handling external HTTP requests on specific routes (e.g., /users), extracting parameters or body payloads, and invoking corresponding service logic.
  • Service (@Injectable): Contains pure business logic (calculations, transformations, database calls, or third-party service calls). Services are decorated with @Injectable() to be automatically injected via NestJS Dependency Injection.

2. Practical Development Guide (Step-by-Step)

1

Global installation of NestJS CLI

The NestJS CLI (Command Line Interface) automates project creation and component generation following Nest architecture best practices.

Terminal
npm install -g @nestjs/cli

:::tip Why use the CLI The CLI avoids manual configuration of TypeScript, Webpack/SWC, ESLint, and Jest, while maintaining a clean and standardized structure across projects. :::

2

Creating the base project

Run the nest new command to initialize a new project named my-nest-app:

Terminal
nest new my-nest-app

During execution, the CLI will prompt you to select a package manager. Select npm (or yarn / pnpm based on your preference).

3

Inspecting project file structure

Navigate to the newly created directory and inspect the generated files:

Terminal
cd my-nest-app

The resulting structure is organized as follows:

File structure
my-nest-app/
├── src/
│ ├── app.controller.spec.ts # Unit tests for main controller
│ ├── app.controller.ts # Base controller with test route ('/')
│ ├── app.module.ts # Root application module
│ ├── app.service.ts # Base service with simple methods
│ └── main.ts # Entry point (starts HTTP server)
├── test/
│ └── app.e2e-spec.ts # End-to-end integration tests
├── nest-cli.json # Nest CLI internal configuration
├── package.json # Dependencies and run scripts
└── tsconfig.json # TypeScript compiler configuration

Explanation of key files inside src/:

  • main.ts: Uses NestFactory.create(AppModule) to instantiate the app and start the server on port 3000 by default.
  • app.module.ts: Application assembly root where root controllers and providers are registered.
  • app.controller.ts: Contains basic HTTP handlers (e.g., GET /).
  • app.service.ts: Returns simple responses (such as "Hello World!").
4

Running the application in development mode

Start the local server in watch mode so it automatically reloads upon saving changes:

Terminal
npm run start:dev

Open your browser at http://localhost:3000 to verify the application responds correctly.

:::info Changing port in main.ts If port 3000 is occupied on your machine, you can modify src/main.ts:

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

async function bootstrap() {
// Instantiate Nest application using root module
const app = await NestFactory.create(AppModule);

// Set HTTP server listening port (e.g., 3001)
await app.listen(3001);
}
bootstrap();

:::

5

Modular generation using CLI

To build an isolated feature (e.g., user management), generating its three core layers is recommended: Module, Controller, and Service.

Open a new terminal tab and enter the following commands:

Terminal
# 1. Generate users module
nest generate module users

# 2. Generate users controller
nest generate controller users

# 3. Generate users service
nest generate service users

:::tip CLI Shortcuts You can use short command aliases in terminal: nest g mo users, nest g co users, and nest g s users. :::

6

Implementing Users Code

Examine the generated code in src/users/ and implement basic communication logic between layers:

src/users/users.service.ts
import { Injectable } from '@nestjs/common';

// Decorator marking class as injectable by NestJS IoC container
@Injectable()
export class UsersService {
// Simulated in-memory collection representing data source
private users = [
{ id: 1, name: 'Alice', email: 'alice@icesi.edu.co' },
{ id: 2, name: 'Bob', email: 'bob@icesi.edu.co' },
];

// Method to return all registered users
findAll() {
return this.users;
}

// Method to return a specific user by ID
findOne(id: number) {
return this.users.find(user => user.id === id);
}
}
src/users/users.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';

// Decorator defining base HTTP route '/users' for all requests in this controller
@Controller('users')
export class UsersController {
// Dependency injection: Nest automatically injects UsersService instance
constructor(private readonly usersService: UsersService) {}

// Handles HTTP GET requests to '/users'
@Get()
getAllUsers() {
return this.usersService.findAll();
}

// Handles HTTP GET requests to '/users/:id'
@Get(':id')
getUserById(@Param('id') id: string) {
// Converts route parameter to number before passing to service
return this.usersService.findOne(Number(id));
}
}
src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

// Decorator registering controllers and providers for the module
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

3. Self-Assessment Quiz

Cargando cuestionario...