Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

NestJS no Node.js: Guia Prático

Atualizado em: 1 de setembro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

Usar NestJS no Node.js oferece uma arquitetura estruturada para APIs, serviços, filas, WebSockets e aplicações corporativas em TypeScript. O framework organiza o código em modules, controllers, providers, guards, interceptors, pipes e exception filters.

Essa estrutura ajuda equipes grandes a manter limites claros entre transporte, regra de negócio e infraestrutura. Porém, decorators e injeção de dependência não garantem automaticamente um bom design. É necessário evitar módulos globais excessivos, providers com muitas responsabilidades, autorização apenas em guards genéricos e acoplamento direto entre controllers e banco.

Neste guia, você aprenderá a criar um projeto NestJS, montar modules e controllers, usar providers, validar entradas, autenticar, autorizar, integrar PostgreSQL, configurar logs, testar e preparar o deploy.

O que é NestJS?

NestJS é um framework progressivo para aplicações Node.js. A documentação oficial do NestJS apresenta controllers, providers, modules e recursos de plataforma. O handbook do TypeScript ajuda a entender decorators usados pelo framework.

Quando usar?

  • APIs grandes;
  • equipes com padrões compartilhados;
  • microserviços;
  • GraphQL;
  • WebSockets;
  • aplicações com filas;
  • domínios com muitos módulos;
  • projetos que valorizam injeção de dependência.

Quando evitar?

  • script pequeno;
  • função serverless mínima;
  • equipe que prefere composição funcional simples;
  • API com poucas rotas e ciclo curto;
  • projeto em que decorators e metadata não são desejados.

Instalando a CLI

npm install -g @nestjs/cli
nest new minha-api

A CLI cria estrutura inicial, scripts, testes e configuração TypeScript. Também é possível configurar manualmente sem instalação global.

Estrutura inicial

src/
  app.controller.ts
  app.module.ts
  app.service.ts
  main.ts

À medida que a aplicação cresce, organize por domínio:

src/
  users/
  orders/
  billing/
  auth/
  shared/

Bootstrap

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.setGlobalPrefix('api');
  await app.listen(process.env.PORT || 3000);
}

bootstrap();

Configuração, validação, logs e shutdown devem ser adicionados antes de escutar.

Module

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
  exports: [UsersService]
})
export class UsersModule {}

O module declara dependências e elementos disponíveis. Exporte apenas o que outros módulos realmente usam.

Controller

import { Controller, Get, Param } from '@nestjs/common';

@Controller('users')
export class UsersController {
  constructor(
    private readonly usersService: UsersService
  ) {}

  @Get(':id')
  findById(@Param('id') id: string) {
    return this.usersService.findById(id);
  }
}

Controllers cuidam do transporte HTTP e delegam a regra de negócio.

Provider

import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  constructor(
    private readonly usersRepository: UsersRepository
  ) {}
}

Providers podem ser serviços, repositories, clients, factories e adapters.

Injeção por token

export const USER_REPOSITORY = Symbol('USER_REPOSITORY');

@Module({
  providers: [
    {
      provide: USER_REPOSITORY,
      useClass: PostgresUsersRepository
    }
  ]
})
export class UsersModule {}

Tokens explícitos ajudam a depender de abstrações. O artigo sobre injeção de dependência será publicado ao final desta rodada.

Request DTO

export class CreateUserDto {
  name: string;
  email: string;
}

Tipos TypeScript desaparecem no runtime. Use validação real com class-validator, Zod ou outra biblioteca.

ValidationPipe

app.useGlobalPipes(new ValidationPipe({
  whitelist: true,
  forbidNonWhitelisted: true,
  transform: true
}));

whitelist remove campos desconhecidos. forbidNonWhitelisted pode rejeitá-los explicitamente, reduzindo mass assignment.

DTO com decorators

import { IsEmail, IsString, MaxLength } from 'class-validator';

export class CreateUserDto {
  @IsString()
  @MaxLength(100)
  name: string;

  @IsEmail()
  email: string;
}

Pipes customizados

Pipes transformam e validam parâmetros antes do controller. Use para UUID, enums e formatos específicos, sem incluir regra de domínio extensa.

Exception filters

Filters transformam exceções em respostas controladas. Não exponha stack, SQL ou mensagens internas.

throw new NotFoundException({
  code: 'USER_NOT_FOUND',
  message: 'Usuário não encontrado'
});

Interceptor

Interceptors podem medir duração, transformar respostas, adicionar cache e observar execução.

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context, next) {
    const startedAt = performance.now();

    return next.handle().pipe(
      finalize(() => {
        logger.info({
          durationMs: performance.now() - startedAt
        }, 'Requisição concluída');
      })
    );
  }
}

Middleware

Middleware executa antes do route handler e pode criar request ID, carregar headers ou aplicar políticas HTTP gerais.

Guard

Guards decidem se uma rota pode prosseguir:

@Injectable()
export class AuthGuard implements CanActivate {
  async canActivate(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest();
    request.user = await authenticate(request);
    return Boolean(request.user);
  }
}

Autenticação

Valide token, sessão ou certificado e coloque uma identidade mínima no request. Consulte JWT Seguro no Node.js e Sessões Seguras no Node.js.

Authorization guard

@Permissions('project.delete')
@Delete(':id')
remove(@Param('id') id: string) {}

Um guard pode verificar permission geral, mas o service ainda precisa validar tenant e ownership do recurso.

Consulte RBAC no Node.js e ABAC no Node.js.

Decorator customizado

export const CurrentUser = createParamDecorator(
  (_, context: ExecutionContext) => {
    return context.switchToHttp().getRequest().user;
  }
);

Retorne uma identidade controlada, não o token completo.

Multi-tenancy

O tenant deve vir da identidade e participar das queries. Consulte Multi-Tenancy no Node.js.

Repository

@Injectable()
export class UsersRepository {
  constructor(private readonly pool: Pool) {}

  async findById({ tenantId, userId }) {
    const result = await this.pool.query(`
      SELECT id, name, email
      FROM users
      WHERE tenant_id = $1
        AND id = $2
    `, [tenantId, userId]);

    return result.rows[0] ?? null;
  }
}

Não acesse banco no controller

Isso mistura HTTP, regra de negócio e persistência, dificultando testes e transações.

Transações

Crie um serviço transacional ou Unit of Work. Consulte Transações PostgreSQL no Node.js.

TypeORM, Prisma e outros

Nest integra com várias bibliotecas. Escolha pela necessidade do projeto, não apenas pela integração pronta. Raw SQL e queries dinâmicas continuam exigindo segurança.

ConfigModule

ConfigModule.forRoot({
  isGlobal: true,
  validate: validateEnvironment
})

Valide configuração no startup. Segredos precisam de cofre e rotação. Consulte Gestão de Segredos no Node.js.

Módulos globais

isGlobal reduz imports, mas aumenta dependências implícitas. Use global apenas para configuração e infraestrutura realmente transversal.

Dynamic modules

Um módulo dinâmico aceita opções e providers:

StorageModule.register({
  driver: 's3'
})

Evite APIs de configuração complexas quando providers explícitos bastam.

Lifecycle hooks

  • OnModuleInit;
  • OnApplicationBootstrap;
  • OnModuleDestroy;
  • BeforeApplicationShutdown;
  • OnApplicationShutdown.

Use para abrir e fechar recursos, sem esconder trabalho demorado.

Graceful shutdown

app.enableShutdownHooks();

Feche pool, filas e clients. Consulte Graceful Shutdown no Node.js.

Fastify adapter

Nest pode rodar sobre Fastify para performance e plugins diferentes. Consulte Fastify com Node.js.

Express adapter

É o padrão comum e oferece amplo ecossistema. Ajuste trust proxy, body limits, timeouts e segurança.

OpenAPI

O módulo Swagger gera documentação a partir de decorators e metadata. Revise o schema gerado e não exponha rotas administrativas indevidamente.

Consulte OpenAPI com Node.js.

GraphQL

Nest oferece integração code-first e schema-first. N+1, complexidade e autorização continuam relevantes. Consulte DataLoader no Node.js.

Microservices

Nest possui transporters para brokers e RPC. Mensagens precisam de idempotência, retry, timeout e DLQ.

Filas

Workers devem criar contexto por job e não reutilizar request-scoped providers sem necessidade.

Provider scopes

  • singleton: padrão e mais eficiente;
  • request: nova instância por request;
  • transient: nova instância por consumidor.

Request scope aumenta custo e pode se propagar pela árvore. Use apenas quando necessário.

AsyncLocalStorage

Para request ID e metadados transversais, considere AsyncLocalStorage no Node.js em vez de tornar muitos providers request-scoped.

Circular dependency

forwardRef() resolve alguns ciclos, mas muitos ciclos indicam limites de módulo ruins. Extraia uma abstração ou reorganize o domínio.

God service

Um service com dezenas de repositories e métodos é um sinal de responsabilidades misturadas. Divida por caso de uso ou agregado.

Cache

Cache interceptors ajudam em respostas simples, mas dados privados precisam de chaves com tenant e usuário.

Rate limiting

Use proteção global e regras por rota. Consulte Rate Limiting no Node.js.

Helmet e CORS

Configure headers de segurança e allowlist de origens. Veja Helmet e CSP no Node.js e CORS em APIs Node.js.

Body limits

Defina limites para JSON e multipart. Consulte Multipart Upload no Node.js.

Logging

Substitua ou integre o logger padrão com logs estruturados. Inclua request ID, rota normalizada, status e duração.

Consulte Logs com Pino no Node.js.

Exception logging

Não registre duas vezes no filter e interceptor. Defina um ponto central e redija segredos.

Métricas

Use interceptor ou middleware para duração, contagem e erros. Monitore também pool, event loop e downstreams.

Health checks

Liveness confirma o processo. Readiness verifica capacidade essencial, sem consultar todas as dependências a cada segundo.

Testes unitários

const module = await Test.createTestingModule({
  providers: [
    UsersService,
    {
      provide: UsersRepository,
      useValue: usersRepositoryMock
    }
  ]
}).compile();

Testes de controller

Mock o service e valide transporte, status e DTO. Regras de negócio pertencem ao service.

Testes de integração

Use banco real em container para repositories e transações.

Testes end-to-end

await request(app.getHttpServer())
  .get('/api/users/42')
  .set('Authorization', token)
  .expect(200);

Override de provider

O testing module permite substituir clients externos. Não transforme todos os testes em mocks que ignoram SQL e serialização reais.

Teste de autorização

Inclua sem token, permission ausente, outro tenant e recurso inexistente.

Teste de validação

Envie campos desconhecidos, strings longas, UUID inválido e tipos incorretos.

Teste de shutdown

Inicie requisição lenta, envie SIGTERM e confirme que o processo drena antes de fechar.

Deploy

Compile no CI e execute o artefato já testado. Não instale dependências ou compile em produção.

Docker

Use multi-stage e usuário não root. Consulte Docker Multi-stage para Node.js.

Erros comuns

  • Controller com regra de negócio: camadas se misturam.
  • Módulo global para tudo: dependências ficam invisíveis.
  • Request scope indiscriminado: custo cresce.
  • Guard como única autorização: recurso fica fora do escopo.
  • DTO sem runtime validation: TypeScript não protege a rede.
  • forwardRef em excesso: módulos estão acoplados.
  • Provider gigante: responsabilidades se acumulam.

Boas práticas

  • Organize por domínio.
  • Mantenha controllers finos.
  • Injete abstrações.
  • Valide inputs globalmente.
  • Autorize por recurso.
  • Evite módulos globais excessivos.
  • Use singleton por padrão.
  • Centralize erros e logs.
  • Teste providers e HTTP.
  • Implemente graceful shutdown.

Conclusão

Usar NestJS no Node.js oferece convenções e ferramentas para aplicações TypeScript grandes. Modules, providers e decorators ajudam a manter uma arquitetura uniforme entre equipes.

O framework funciona melhor quando controllers permanecem finos, providers possuem responsabilidades claras e autorização chega até o recurso. Com validação, testes, observabilidade e shutdown controlado, NestJS fornece estrutura sem transformar decorators em dependências implícitas difíceis de manter.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita