Node.js vs Go: Benchmark Completo com NestJS, Gin e PostgreSQL
Testei 800 conexões simultâneas, operações de banco, CPU-bound e mais. Os números não mentem.
Toda discussão sobre "qual linguagem é melhor" costuma terminar em opiniões. Decidi acabar com o achismo criando duas APIs idênticas, uma em NestJS (Node.js) e outra em Gin (Go), com PostgreSQL, e executando benchmarks de produção real.
O Setup
- Hardware: MacBook Pro M1, 16GB RAM
- Banco: PostgreSQL 16 (Docker)
- Ferramenta: wrk (HTTP benchmark)
Ambas as APIs implementam os seguintes requisitos:
- Endpoints de CPU (JSON, hash, fibonacci)
- Endpoints de banco (CRUD, agregação)
- Pool de conexões com 20 conexões máximas
Os Resultados
🚀 Performance Pura (Sem Banco)
| Teste | NestJS | Gin | Vantagem Go |
|---|---|---|---|
| Health Check | 16k req/s | 93k req/s | 5.8x |
| JSON (100 obj) | 4.3k req/s | 28k req/s | 6.4x |
| Fibonacci (n=30) | 96 req/s | 1.8k req/s | 19x |
| Bcrypt Hash | 64 req/s | 91 req/s | 1.4x |
Destaques:
- O Go é 19x mais rápido em processamento CPU-bound puro.
- Em bcrypt, a diferença cai para 1.4x, pois o Node utiliza bindings em C.
🔥 Stress Test (800 conexões, 45 segundos)
| Métrica | NestJS | Gin |
|---|---|---|
| Requests/sec | 16k | 90k |
| Latência p99 | 63ms | 15ms |
| Timeouts | 481 | 0 |
O dado mais crítico: O NestJS apresentou 481 timeouts, enquanto o Gin teve zero. Em produção, timeouts representam clientes recebendo erros diretamente.
🗄️ Com PostgreSQL (200 conexões)
| Operação | NestJS | Gin | Vantagem Go |
|---|---|---|---|
| SELECT 1 row | 7.7k req/s | 18.7k req/s | 2.4x |
| SELECT 100 rows | 4.7k req/s | 9.3k req/s | 2.0x |
| Aggregation | 7.7k req/s | 13.4k req/s | 1.7x |
Insight: A diferença caiu de uma escala de 5-19x para um intervalo entre 1.7x e 2.4x. Isso indica que o banco de dados se torna o gargalo principal do sistema.
A latência p99, contudo, continua muito diferente:
- List 100 rows: NestJS 158ms vs Gin 33ms (uma latência 4.7x menor).
💾 Uso de Memória
| Momento | NestJS | Gin |
|---|---|---|
| Startup | 68 MB | 11 MB |
| Após stress | 85 MB | 52 MB |
O Go consome entre 40% e 80% menos memória que o Node.js em cenários similares.
O Que Isso Significa na Prática
✅ Use Go (Gin) quando:
- A performance for crítica: APIs que precisam sustentar volumes superiores a 10k req/s.
- O domínio for CPU-bound: tarefas intensas de processamento e transformações de dados.
- A latência p99 for prioridade: casos com SLAs (Service Level Agreements) muito apertados.
- Os recursos forem limitados: ambientes de Kubernetes com limites rígidos de memória.
- Houver necessidade de estabilidade sob carga: situações onde evitar timeouts for essencial.
✅ Use Node.js (NestJS) quando:
- A prioridade for velocidade de desenvolvimento: aproveitando recursos como TypeScript, Injeção de Dependência e decorators.
- O time for focado em JavaScript: reduzindo drasticamente a curva de aprendizado.
- O domínio for I/O-bound: situações onde a diferença de performance no banco de dados é aceitável para o negócio.
- Depender do ecossistema NPM: necessidade de bibliotecas específicas já consolidadas na comunidade.
Reproduza Você Mesmo
# Clone o repositório
git clone https://github.com/zghost10/go-vs-node.git
# Inicie PostgreSQL
docker-compose up -d
# Inicie as APIs
cd nestjs-api && npm install && npm run build && node dist/main.js &
cd gin-api && go build && ./gin-api &
# Benchmark
wrk -t8 -c800 -d45s --latency http://localhost:3000/health
wrk -t8 -c800 -d45s --latency http://localhost:8080/health
wrk -t4 -c200 -d15s --latency http://localhost:3000/db/users/active
wrk -t4 -c200 -d15s --latency http://localhost:8080/db/users/active