Saltar para o conteúdo
Setup Node.js para Produção

Setup Node.js para Produção

Checklist para levar uma aplicação Node.js de desenvolvimento para produção com segurança.

1. Variáveis de ambiente

Nunca hardcode configurações no código:

# .env (nunca commite este arquivo)
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:pass@host:5432/db
JWT_SECRET=seu-secret-muito-seguro-aqui
// src/config.ts — valide na inicialização
import { z } from 'zod'

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production', 'test']),
  PORT: z.coerce.number().default(3000),
  DATABASE_URL: z.string().url(),
  JWT_SECRET: z.string().min(32),
})

export const config = envSchema.parse(process.env)

2. Graceful shutdown

async function shutdown(signal: string) {
  console.log(`Recebido ${signal}, encerrando...`)

  await server.close()
  await db.end()

  process.exit(0)
}

process.on('SIGTERM', () => shutdown('SIGTERM'))
process.on('SIGINT', () => shutdown('SIGINT'))

3. Logging estruturado

import pino from 'pino'

export const logger = pino({
  level: process.env.LOG_LEVEL ?? 'info',
  formatters: {
    level: (label) => ({ level: label }),
  },
})

// Use assim:
logger.info({ userId, action: 'login' }, 'Usuário autenticado')
// Nunca: logger.info(`Usuário ${userId} fez login`)

4. Health checks

app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() })
})

app.get('/health/ready', async (req, res) => {
  try {
    await db.query('SELECT 1')
    res.json({ status: 'ready' })
  } catch {
    res.status(503).json({ status: 'not ready' })
  }
})

5. Segurança básica

npm install helmet cors express-rate-limit
import helmet from 'helmet'
import cors from 'cors'
import rateLimit from 'express-rate-limit'

app.use(helmet())
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') }))
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }))

6. Monitoramento de erros

// Handler de erros global
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  logger.error({ err, path: req.path }, 'Erro não tratado')

  res.status(500).json({
    error: process.env.NODE_ENV === 'production'
      ? 'Erro interno'
      : err.message,
  })
})

// Erros não capturados
process.on('unhandledRejection', (reason) => {
  logger.fatal({ reason }, 'Promise rejeitada não tratada')
  process.exit(1)
})

Checklist final

  • Variáveis de ambiente validadas na inicialização
  • Graceful shutdown implementado
  • Logging estruturado (JSON) configurado
  • Health check e readiness check expostos
  • Helmet + CORS + rate limiting configurados
  • Handler de erros global implementado
  • Métricas expostas (Prometheus ou CloudWatch)
  • Processo gerenciado por PM2 ou container