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...