Skip to main content

First Steps with NestJS

NestJS structures backend applications using a modular architecture inspired by enterprise-grade patterns. In this hands-on guide, you will learn how to install the CLI, bootstrap a new project, understand its internal layout, and build your own modules, controllers, and services.


1. Architecture and Component Fundamentals​

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

Main Components Overview:​

  • Module (@Module): The fundamental organizational unit in NestJS. It bundles cohesive controllers and providers (services), establishing clear encapsulation boundaries for a scalable modular system.
  • Controller (@Controller): Responsible for handling incoming HTTP requests on specified route paths (such as /users), unpacking parameters or request body payloads, and delegating execution to the appropriate service method.
  • Service (@Injectable): Contains pure business logic (calculations, transformations, database calls, or external API communication). Services are decorated with @Injectable() so they can be injected automatically by NestJS's IoC container.

2. Step-by-Step Hands-On Guide​

1

Global NestJS CLI Installation

The NestJS Command Line Interface (CLI) automates project bootstrapping and component generation according to architectural best practices.

Terminal
npm install -g @nestjs/cli
Why Use the CLI

The CLI prevents manual configuration of TypeScript, Webpack/SWC, ESLint, and Jest, maintaining a clean and standardized structure across projects.

2

Bootstrapping the Base Project

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

Terminal
nest new my-nest-app

During execution, the CLI will ask which package manager you prefer. Select npm (or yarn / pnpm depending on your setup).

3

Inspecting Project Anatomy

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

Terminal
cd my-nest-app

The resulting folder structure is organized as follows:

File Structure
my-nest-app/
├── src/
│ ├── app.controller.spec.ts # Unit tests for root controller
│ ├── app.controller.ts # Base controller with test endpoint ('/')
│ ├── app.module.ts # Root module of the application
│ ├── app.service.ts # Base service with simple methods
│ └── main.ts # Application entry point (starts HTTP server)
├── test/
│ └── app.e2e-spec.ts # End-to-end test suite
├── nest-cli.json # NestJS CLI configuration
├── package.json # Dependencies and npm scripts
└── tsconfig.json # TypeScript compiler options

Core files in src/:

  • main.ts: Uses NestFactory.create(AppModule) to instantiate the app and bind the server to port 3000 by default.
  • app.module.ts: The root module that mounts the application and registers base providers and controllers.
  • app.controller.ts: Contains sample HTTP route handlers (e.g., GET /).
  • app.service.ts: Returns sample responses (such as "Hello World!").
4

Running the App in Development Mode

Start the local server in watch mode so that file changes are automatically detected and reloaded:

Terminal
npm run start:dev

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

Changing Port in main.ts

If port 3000 is occupied on your machine, you can change it in src/main.ts:

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

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

// Define HTTP listen port (e.g., 3001)
await app.listen(3001);
}
bootstrap();
5

Generating Modules with the CLI

To build an isolated feature (such as user management), it is recommended to generate its three architectural layers: Module, Controller, and Service.

Open a new terminal tab and run:

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
CLI Shortcuts

You can use shorthand aliases in your terminal: nest g mo users, nest g co users, and nest g s users.

6

Implementing Users Feature Logic

Inspect the code generated under src/users/ and implement the basic inter-layer communication:

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

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

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

// 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 setting the base route path '/users' for this controller
@Controller('users')
export class UsersController {
// Dependency injection: Nest automatically injects UsersService
constructor(private readonly usersService: UsersService) {}

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

// Handles HTTP GET to '/users/:id'
@Get(':id')
getUserById(@Param('id') id: string) {
// Cast route param string 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 of this module
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

3. Self-Assessment Quiz​

Cargando cuestionario...