Hello everyone. I recently conducted an exhaustive benchmark to answer a classic question in backend teams: does it make sense to migrate to Go, or is NestJS enough?
There is no magic answer, but data helps decide. Here is a summary of the most important findings.
🏗️ The Scenario
I compared two typical architectures running in Docker on the same machine (M4 Pro):
- NestJS (Node 22) + Prisma v6 (Productivity approach)
- Go (1.24) + GORM (Performance approach)
Both connected to PostgreSQL 15 and subjected to stress tests (gRPC and HTTP) simulating a real environment.
🧪 Methodology: What did we measure?
To truly understand the differences, I divided the tests into two key scenarios:
Small Data (1x1 Insert):
Simulates typical transactional traffic of a REST/gRPC API. We receive an object, validate it, and save it. Here we measure the framework's base latency.Large Data (Batch Insert of 1000 elements):
Simulates bulk load processes, ETLs, or event ingestion. We send arrays of 1000 objects that must be deserialized, validated, and saved in a single transaction. This is where CPU and Garbage Collector suffer the most.
📊 The Results
1. Small Data: The Surprise
In low load or unit insert scenarios, the difference was minimal. Go obtained a latency improvement of just ~10% over NestJS.
Conclusion: For standard CRUD operations, NestJS is incredibly efficient, and the performance difference rarely justifies losing TypeScript's productivity.
2. Large Data: The Breaking Point
The story changes drastically when processing massive batches (arrays of 1000 elements) under high concurrency.
Scenario: 100 RPS constant (Bulk Inserts)
| Service | Real Throughput | P95 Latency | Success Rate |
|---|---|---|---|
| Go gRPC | 85 RPS | 71.88 ms | 100% |
| NestJS gRPC | 78 RPS | 98.44 ms | ~85% |
What happened here?
- Serialization: Node.js (V8) has a higher cost when serializing/deserializing large volumes of JSON compared to Go Structs and Protobuf.
- Connection Pool: Under extreme pressure, the Prisma connection pool started to saturate (
P2024errors), causing NestJS to lose ~15% of requests. - Stability: Go maintained 100% success and more predictable latencies, thanks to its goroutine management and a more efficient GC for this type of load.
⚖️ Conclusion: When to use which?
Based on the data, here is my pragmatic recommendation:
✅ Stay with NestJS if:
- You are building an MVP or validating a product.
- Your team already knows TypeScript and you value development speed.
- The load is moderate (< 300 RPS) and standard CRUD operations (Small Data).
- BFF (Backend for Frontend): If you only need to orchestrate calls to a few services and the serialization load is low.
🚀 Migrate to Go if:
- Complex BFF: If your BFF needs to call many microservices, add heavy logic, serialize large volumes of data, and perform massive fan-out, Go will handle concurrency much better.
- Your system constantly performs massive Bulk Operations / ETL (Large Data).
- You need to handle thousands of concurrent connections (e.g., Gateways, massive Websockets).
- You have very strict latency SLAs where Node's Garbage Collector spikes are unacceptable.
- Infrastructure is expensive and you need to squeeze every CPU cycle.
📖 Read the full analysis
This post is a summary. The detailed analysis (with all tables, charts, hardware configuration, and error analysis) is public and free.
👉 Read the full article on Buy Me a Coffee
💌 Special Acknowledgments
To a girl who, without knowing it, pushed me to keep creating and programming in my free time. To the one who was once my spark: for "YLP", with gratitude... and with scars that also teach.
If you find this analysis useful, any feedback is welcome!
Top comments (0)