Voltar ao blog Tutoriais

Como fazer deploy de uma aplicação NestJS no Brasil

Um guia direto para publicar uma API NestJS em container, com TypeScript, variáveis de ambiente e HTTPS em infraestrutura brasileira usando a Guara Cloud.

7 min de leitura

Por Guara Cloud Editorial

Testado com Node.js 20 / NestJS 10 / Docker / Guara Cloud

NestJS tem uma pegadinha na hora de deploy que não existe em projetos Express puros: o build do TypeScript precisa rodar antes do container iniciar, e a imagem de produção não deveria carregar o compilador nem os arquivos .ts. Muita gente resolve isso com imagens de 1GB ou com um Dockerfile que copia tudo pra dentro. Dá pra fazer melhor.

Este tutorial cobre o caminho inteiro, do Dockerfile multi-stage até o serviço rodando com HTTPS na Guara Cloud, em infraestrutura no Brasil.

Resposta rápida

Para publicar uma aplicação NestJS no Brasil, compile o TypeScript em um estágio de build do Dockerfile, copie apenas o diretório dist e as dependências de produção para a imagem final, escute na porta definida por ENV PORT e publique o container na Guara Cloud. A plataforma cuida de HTTPS, domínio público, logs e cobra em Real.

Principais pontos

  • Use Dockerfile multi-stage. O estágio de build compila TypeScript, o estágio final carrega só dist/ e node_modules de produção.
  • Leia PORT do ambiente. Não hardcode 3000.
  • Use o ConfigModule do NestJS para ler variáveis de ambiente com tipagem.
  • Configure segredos pelo painel da Guara Cloud, nunca no repositório.
  • Adicione um health check com @nestjs/terminus para a plataforma saber quando o serviço está pronto.

Quando este tutorial se aplica

Use este fluxo para APIs REST, GraphQL (com Apollo ou Mercurius) e microsserviços construídos com NestJS. Se a aplicação usa fila (BullMQ), websocket (Gateway) ou gRPC, o container funciona da mesma forma. A diferença fica nas portas expostas e nas variáveis de ambiente.

Quando não usar este fluxo

Se a aplicação é puramente um worker sem porta HTTP (só consome fila), o deploy é similar mas você não precisa do health check HTTP. Se o projeto usa serverless (Lambda, Cloud Functions), este guia não se aplica. Para monorepos com Nx onde vários apps NestJS convivem, ajuste os caminhos de build no Dockerfile para apontar para o app correto.

Antes de começar

  • Um projeto NestJS criado com @nestjs/cli (nest new meu-app)
  • Node.js 20+ instalado localmente para testes
  • Docker instalado para validar a imagem
  • Uma conta na Guara Cloud

1. Configure a porta via variável de ambiente

O NestJS padrão escuta em 3000. Em container, a plataforma define a porta. Abra src/main.ts e ajuste:

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

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const port = Number(process.env.PORT ?? 3000);
await app.listen(port, '0.0.0.0');
}
bootstrap();

O 0.0.0.0 é obrigatório. Sem ele, a aplicação escuta apenas no loopback e o balanceador de carga não consegue alcançar o container.

2. Dockerfile multi-stage para NestJS

Aqui está o ponto que separa uma imagem de 50MB de uma de 800MB. O primeiro estágio instala tudo, compila TypeScript e roda os testes se quiser. O segundo estágio copia só o que precisa pra rodar.

Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
ENV NODE_ENV=production
CMD ["node", "dist/main.js"]

Esse Dockerfile produz uma imagem com aproximadamente 80MB. O npm ci --omit=dev no estágio final garante que TypeScript, ESLint e Jest não vão pra produção.

3. Configure variáveis de ambiente com ConfigModule

O NestJS tem um módulo oficial para tipar e validar variáveis de ambiente. Se ainda não instalou:

Instale o ConfigModule
npm install @nestjs/config

Depois, registre no AppModule:

app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
imports: [
  ConfigModule.forRoot({
    isGlobal: true,
  }),
],
})
export class AppModule {}

No painel da Guara Cloud, configure as variáveis que a aplicação consome:

Variáveis de ambiente comuns

Nome Valor
NODE_ENV production
PORT 3000
DATABASE_URL postgres://usuario:senha@host:5432/meubanco
JWT_SECRET string-aleatoria-longa

Nunca commite .env no repositório. Use .env.example como referência com valores fictícios.

4. Adicione health check

A Guara Cloud usa probes HTTP para decidir se o container está saudável. Instale o Terminus e crie um endpoint simples:

Instale Terminus
npm install @nestjs/terminus
health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheckService, HealthCheck, HttpHealthIndicator } from '@nestjs/terminus';

@Controller('health')
export class HealthController {
constructor(
  private health: HealthCheckService,
  private http: HttpHealthIndicator,
) {}

@Get()
@HealthCheck()
check() {
  return this.health.check([
    () => this.http.pingCheck('ping', 'https://www.google.com'),
  ]);
}
}

Para algo mais simples (sem dependências externas), basta retornar { status: 'ok' } em /health. A plataforma só precisa de um 200 OK.

5. Faça o deploy na Guara Cloud

Com o repositório no GitHub e o Dockerfile na raiz, o processo na Guara Cloud é:

Passo a passo no painel

  1. Crie um novo serviço e conecte o repositório GitHub
  2. A plataforma detecta o Dockerfile automaticamente
  3. Confirme a porta HTTP (o valor de PORT, geralmente 3000)
  4. Adicione as variáveis de ambiente pelo painel
  5. Inicie o deploy e acompanhe os logs de build em tempo real

O build roda o Dockerfile completo: instala dependências, compila TypeScript, gera a imagem final. O primeiro deploy leva entre 2 e 4 minutos dependendo do tamanho do projeto. Deploys seguintes são mais rápidos por causa do cache de camadas Docker.

6. Valide o serviço em produção

Após o deploy completar, verifique:

  • A URL pública responde com 200.
  • O endpoint /health retorna status ok.
  • Os logs mostram a aplicação escutando na porta correta.
  • O consumo de CPU e memória está dentro do esperado (no painel da Guara Cloud, aba de observabilidade).

Se algo falhar, os logs de build e de runtime ficam disponíveis no painel. A maioria dos problemas aparece nos primeiros segundos.

Problemas comuns

Problema O container sobe e morre imediatamente
Solução Verifique se main.ts escuta em 0.0.0.0 e usa process.env.PORT. Localmente, rode "docker run -e PORT=3000 -p 3000:3000 minha-imagem" para reproduzir.
Problema Erro de módulo não encontrado (Cannot find module)
Solução O dist/ não foi copiado para a imagem final. Confirme a linha "COPY --from=builder /app/dist ./dist" no Dockerfile.
Problema A aplicação conecta no banco local em vez do banco da nuvem
Solução Verifique se DATABASE_URL está configurada no painel da Guara Cloud e se o ConfigModule está lendo a variável corretamente.
Problema Build do Docker demora mais de 10 minutos
Solução Garanta que node_modules e dist estão no .dockerignore. Camadas de npm ci são reutilizadas entre builds quando package.json não muda.
Problema O health check falha mas a aplicação responde normalmente
Solução O probe pode estar batendo antes da aplicação inicializar. Aumente o initialDelaySeconds ou simplifique o health check para não depender de recursos externos.

Dicas de performance para NestJS em container

Algumas configurações fazem diferença real quando a aplicação está sob carga:

  • Limite de workers. O NestJS não clusteriza sozinho. Se precisar de múltiplos processos, use o @nestjs/microservices com múltiplas réplicas na Guara Cloud (escale horizontalmente) em vez de PM2 dentro do container.

  • Lazy loading de módulos. Módulos carregados com LazyModuleLoader reduzem o tempo de cold start em aplicações com muitos módulos que nem toda request usa.

  • Fastify em vez de Express. Troque o adapter para @nestjs/platform-fastify se a API recebe mais de mil requests por segundo. A diferença de throughput é mensurável.

NestJS funciona com Docker sem modificações no projeto?

Quase. Basta garantir que main.ts escute em 0.0.0.0 e use process.env.PORT. O resto (Dockerfile, variáveis, build) é configuração externa ao código NestJS.

Como usar PostgreSQL com NestJS na Guara Cloud?

Crie o PostgreSQL pelo catálogo da Guara Cloud, copie a URL de conexão e configure como DATABASE_URL nas variáveis de ambiente do serviço. Use TypeORM ou Prisma no NestJS para consumir a conexão.

A cobrança é em Real?

Sim. A Guara Cloud cobra em BRL via Stripe. Sem conversão de dólar, sem surpresa no cartão.

Preciso de Nginx na frente do NestJS?

Não. A Guara Cloud entrega HTTPS, domínio público e roteamento sem você configurar Nginx ou certificados TLS manualmente.

Publique sua API NestJS na Guara Cloud

Deploy com Docker, HTTPS gerenciado, logs e cobrança em Real. Infraestrutura em São Paulo.

Começar grátis