Nest es un framework de desarrollo backend para Node que se basa en TypeScript. Recordemos que cuando hablamos de framework nos referimos a un conjunto de herramientas y componentes listos para usar, con una estructura organizada que hace todo más fácil y rápido cuando estás desarrollando aplicaciones. Resumiendo, nos da todo lo necesario para que no tengamos que inventar soluciones desde cero, ahorrando tiempo y esfuerzo.
Nest está basado en Angular (framework de desarrollo web creado por Google) y utiliza conceptos como módulos, controladores, proveedores (servicios) y decoradores para estructurar aplicaciones de manera escalable y mantenible. ¿Quééé? ¿Módulos? ¿Controladores? ¿Qué son estas “cosas”? Tranquilo, lo vamos a explicar en un ratito.
Nest combina elementos de la programación orientada a objetos (OOP), la programación funcional (FP) y la programación reactiva (FRP), lo que lo hace versátil para construir aplicaciones robustas y eficientes. Si trabajaste con Node, seguramente conocés cómo construir una API REST con Express. Nest lo utiliza por defecto como base, aunque también puede funcionar con Fastify para mejorar el rendimiento. ⚡
Entonces, ya sabemos que Nest está basado en buenas prácticas y nos ofrece una arquitectura sólida... pero ¿por qué deberíamos usarlo en lugar de seguir con Express? ¿Qué ventajas concretas nos da?
¿Por qué usar NestJS? 🤖
NestJS resuelve muchos de los problemas que aparecen cuando una aplicación en Node empieza a crecer. Si bien con Express podemos armar un backend desde cero y tener el control total, eso también implica que debemos encargarnos manualmente de organizar el código, aplicar buenas prácticas, manejar dependencias, validar datos, documentar la API, testear, etc. Con Nest, gran parte de eso ya viene incorporado.Algunas ventajas que ofrece NestJS:
- ✔️ Estructura clara desde el inicio: promueve una arquitectura bien organizada, dividiendo tu aplicación en módulos, controladores y servicios desde el comienzo.
- ✔️ Basado en TypeScript
- ✔️ Inyección de dependencias integrada: facilita reutilizar código, testear y mantener el proyecto.
- ✔️ Herramientas listas para usar: validaciones, Swagger, middlewares, interceptores, configuración por entorno y más.
- ✔️ Soporte oficial para patrones avanzados: microservicios, GraphQL, WebSockets, gRPC, etc.
🟩 ¿Cuándo conviene usar NestJS?
Usar NestJS tiene sentido cuando:- Estás construyendo una aplicación de mediana o gran escala, o con proyección a crecer 📈.
- Necesitás una arquitectura modular, clara y fácil de mantener.
- Tu aplicación incluye múltiples capas (como validaciones, seguridad, lógica de negocio, etc.).
- Vas a trabajar en equipo y necesitás una base estandarizada para colaborar 🤝.
🟥 ¿Cuándo no conviene usar NestJS?
Aunque es un gran framework, NestJS no es ideal en todos los escenarios:- Si estás haciendo un script simple o microservicio muy puntual, Nest puede ser demasiado pesado.
- Si tu aplicación necesita tiempos de arranque ultra bajos, como en algunos entornos serverless, el overhead inicial de Nest podría ser una desventaja ⏱️.
- Si buscás algo extremadamente minimalista y sin capas adicionales, quizás Express puro sea más directo.
Para que te quedes con la idea de lo que vimos hasta acá, NestJS es una base sólida y escalable para crear aplicaciones backend desde el primer día. No siempre es la elección adecuada, pero en los proyectos que lo piden, puede ahorrarte más de un dolor de cabeza.
Bueno, hasta ahora mencionamos pura teoría. Pasemos a ver un poco de código, que es lo que nos gusta 😎. Para crear un proyecto en Nest, debemos tener instalado Node en nuestro sistema. Si no lo tenés, te dejo el link oficial: ¡Instalá NodeJS aquí!. La versión mínima de Node que se recomienda para usar con Nest es la 16.
Ahora instalemos Nest. Para hacerlo, ejecutamos el siguiente comando:
npm i -g @nestjs/cli
nest new nombre_del_proyecto

Cuando termine de instalar todo, nos aparecerá lo siguiente:

Veamos las carpetas y archivos que se crearon:

Controllers 🎮
Un controller es una clase que maneja las solicitudes entrantes de la aplicación. Su función principal es recibir las peticiones HTTP, procesarlas (directamente o delegando a un servicio) y devolver una respuesta adecuada.En el archivo app.controller.ts tenemos este código:
import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller('mi-api') export class AppController { constructor(private readonly appService: AppService) {} @Get('mi-endpoint') getHello(): string { return this.appService.getHello(); } }El decorador @Controller() en NestJS se usa para definir una clase como un controlador que maneja rutas HTTP. Permite establecer una ruta base para los endpoints dentro de la clase y se combina con otros decoradores como @Get(), @Post(), @Body(), y @Param(). Por ejemplo, @Controller('mi-api') hace que todos los métodos dentro del controlador respondan bajo la ruta
/mi-api
. A su vez, @Get('mi-endpoint') hace que ese método responda a la ruta /mi-api/mi-endpoint
.
En el constructor de la clase podemos ver que tenemos el atributo appService, que va a contener una instancia de AppService. La instancia la va a inyectar Nest mediante su sistema de inyección de dependencias.
La inyección de dependencias es un patrón de diseño que permite que las clases reciban sus dependencias desde el exterior, en lugar de crearlas internamente. Esto facilita la gestión y el testing del código. En NestJS, se usa el decorador
@Injectable()
para definir servicios que pueden ser inyectados en controladores u otros servicios mediante el constructor. El framework se encarga de resolver y proporcionar automáticamente las instancias necesarias.
Profundizaremos en este tema en una publicación posterior ¡estate atento! 🧐
Providers 🛠️
Un provider es un componente que puede ser inyectado en otras partes de la aplicación (como controladores o servicios) para proporcionar funcionalidades, como la lógica de negocio o el acceso a bases de datos.En nuestro caso, tenemos como provider a AppService. Vemos el código del archivo app.service.ts:
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } }Como se mencionó anteriormente, el decorador
@Injectable()
se usa para marcar la clase como inyectable, lo que permite que el sistema de inyección de dependencias de Nest la gestione y la pueda inyectar en otras clases.
Por defecto, se configura el provider como singleton (una única instancia compartida en toda la aplicación),
pero también podríamos configurarlo como
@Injectable({ scope: Scope.REQUEST })
(se crea una nueva instancia por cada request)
o @Injectable({ scope: Scope.TRANSIENT })
(se crea una nueva instancia cada vez que se inyecta).
Más info de scopes aquí
Modules 📦
Un módulo es una unidad de organización que agrupa componentes relacionados, como controladores, servicios y otros módulos. Sirve para estructurar y organizar la aplicación en partes más pequeñas y manejables, facilitando la inyección de dependencias y el mantenimiento del código.En nuestro caso tenemos como módulo a AppModule. Veamos el código del archivo 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 {}La propiedad imports sirve para importar otros módulos con sus respectivos providers y controllers, y poder usarlos dentro del módulo actual. NestJS gestiona un contenedor de dependencias para cada módulo, y los providers declarados dentro de ese contenedor no están disponibles automáticamente en otros módulos. Por eso, para usar un servicio de otro módulo, debés importarlo.
La propiedad controllers registra clases encargadas de manejar las rutas HTTP. Nest las instancia, inyecta sus dependencias y las conecta al router subyacente de la plataforma (como Express o Fastify), permitiendo que respondan a solicitudes del cliente según las rutas y métodos definidos.
La propiedad providers registra clases (decoradas con
@Injectable()
) que contienen lógica de negocio o utilidades. Nest las administra dentro de su sistema de inyección de dependencias, creando instancias singleton que pueden ser compartidas dentro del módulo o exportadas a otros.
Iniciar la aplicación
Para iniciar la aplicación tenemos el archivo main.ts, en el mismo se encuentra el siguiente código: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();
NestFactory
es una clase que provee NestJS para crear instancias de la aplicación. Es parte del núcleo del framework y se encarga de iniciar todo el ciclo de vida de la app.
Cuando ejecutamos
NestFactory.create(AppModule)
, lo que estamos haciendo es arrancar nuestra aplicación a partir del módulo raíz (en este caso, AppModule
), que contiene los controladores, servicios y demás componentes que definimos.
Este proceso inicializa el sistema de inyección de dependencias, carga los módulos y deja lista la aplicación para empezar a escuchar peticiones HTTP. Es una de las primeras líneas que se ejecutan en cualquier proyecto NestJS.
Sin embargo, con esto la aplicación aún no está escuchando en ningún puerto. Para eso, necesitamos ejecutar:
await app.listen(process.env.PORT ?? 3000);
Este método listen()
es el que inicia efectivamente el servidor HTTP, y le dice a NestJS que empiece a escuchar peticiones entrantes en el puerto indicado (por ejemplo, el 3000
).
🔁 Diferencia clave:
create()
prepara la aplicación: configura módulos, servicios, inyección de dependencias, etc.listen()
la pone en marcha: inicia el servidor y lo deja listo para recibir peticiones.
create()
es como encender el motor de un auto: todo está preparado y listo para funcionar.listen()
es como pisar el acelerador: hace que el auto (la aplicación) empiece a moverse y a responder.
Para arrancar la aplicación ejecutemos este comando que levanta la app en modo dev:
npm run start:dev
[Nest] 52441 - 08/05/2025, 3:47:41 PM LOG [NestFactory] Starting Nest application... [Nest] 52441 - 08/05/2025, 3:47:41 PM LOG [InstanceLoader] AppModule dependencies initialized +76ms [Nest] 52441 - 08/05/2025, 3:47:41 PM LOG [RoutesResolver] AppController {/mi-api}: +8ms [Nest] 52441 - 08/05/2025, 3:47:41 PM LOG [RouterExplorer] Mapped {/mi-api/mi-endpoint, GET} route +29ms [Nest] 52441 - 08/05/2025, 3:47:41 PM LOG [NestApplication] Nest application successfully started +5msEl último log nos indica que la aplicación ya se encuentra levantada. Probémosla con Postman ejecutando la request GET
http://localhost:3000/mi-api/mi-endpoint
. La ruta es la que definimos en el controlador anteriormente.
En Postman veremos esto:

getHello()
del servicio.
🌐 Si no tenés Postman, también podés copiar y pegar la URL
"http://localhost:3000/mi-api/mi-endpoint" en tu navegador preferido y vas a visualizar el mensaje de la API.
🙌 ¡Gracias por leer!
Espero que esta guía te haya servido como una buena puerta de entrada a NestJS y te haya aclarado esos primeros pasos que a veces pueden parecer confusos.En el próximo post vamos a meternos con un tema fundamental: la inyección de dependencias 🧩. Vas a ver cómo funciona dentro del framework y por qué te puede ahorrar muchos dolores de cabeza a futuro.
¡Nos leemos pronto! 👋