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