🔬 NestJS vs Go: Lo que los datos dicen ...

🔬 NestJS vs Go: Lo que los datos dicen sobre cuándo usar cada uno

Mar 08, 2026

imageHola a todos. Hoy comparto los resultados de un benchmark que hice para intentar responder una pregunta que se repite mucho en equipos de backend: ¿tiene sentido migrar a Go, o alcanza con NestJS?

No hay respuesta mágica. Pero los datos ayudan a tomar mejores decisiones.

🇬🇧 Read this post in English

Mira la presentación completa aquí (Google Drive)


🎯 ¿Por qué este proyecto?

Go tiene una curva de aprendizaje alta. No es TypeScript, no tiene el ecosistema de NestJS, y contratar Go developers cuesta más. Entonces, antes de recomendar algo así a un equipo o negocio, necesitaba datos reales que respondieran cuándo vale la pena el esfuerzo, y cuándo no.

La idea no era "Go gana, NestJS pierde". Era entender en qué contextos cada uno brilla, y cuándo el costo de adoptar Go se justifica.

🏗️ La Arquitectura del Benchmark

Desarrollé una suite completa de benchmarking con cuatro componentes orquestados vía Docker Compose en una red interna aislada:

  1. NestJS App (Node.js 22): DDD + Prisma v6. El enfoque orientado a productividad.

  2. Go App (Golang 1.24): Clean Architecture + GORM. El enfoque orientado a rendimiento.

  3. Dashboard (Next.js 16): Actúa como BFF (Backend-for-Frontend) y motor de inyección de carga. Permite simular cómo se comporta una aplicación full-stack real bajo estrés — algo más cercano a producción que usar k6 directamente.

  4. PostgreSQL 15: Base de datos compartida. Ambos servicios apuntan a la misma instancia y tabla, con UUIDs generados en la capa de aplicación para una comparativa justa.

🛠️ Metodología

Cada servidor mide internamente el tiempo desde que recibe la petición hasta que confirma la inserción en PostgreSQL (processing_time_ns), eliminando el ruido de red. Las métricas reportadas son percentiles de latencia (p95), no promedios, ya que exponen mejor los picos del Garbage Collector y la estabilidad real del sistema.

Dos esquemas de carga:

  • Modo RPS (Sistema Abierto): RPS fijo, independiente del estado del backend — simula saturación.

  • Modo Paralelo (Sistema Cerrado): Usuarios virtuales concurrentes que esperan la respuesta antes de reenviar.


💻 Entorno de Ejecución

Todas las pruebas se ejecutaron en la misma máquina local, con todos los contenedores corriendo simultáneamente vía Docker Compose. No se usó infraestructura aislada de servidores.

image

⚠️ Importante: El hecho de que todos los servicios corran en la misma máquina significa que compiten por los mismos recursos físicos (CPU, memoria, I/O de disco). Esto favorece que los resultados sean conservadores — en un entorno de servidores dedicados, la ventaja de Go en latencia y throughput sería aún más pronunciada.


📊 Resultados por Escenario

🔵 Small Data — Modo RPS

Corrida representativa: 500 RPS / 60s / Ramp-up 3s

image

📌 Con carga moderada y payloads pequeños, la diferencia es real pero pequeña (~10%). Ambos 100% de success rate. En este escenario, el argumento para migrar a Go es débil desde el punto de vista de negocio.


🟠 Small Data — Modo Paralelo

Corrida representativa: 50 vUs / Ramp-up 5s / Duración 60s

image

📌 Con 200 vUs, la ventaja de Go se amplía (~15-20% mejor server time), pero NestJS sigue siendo estable. La brecha no justifica sola una migración.


🟡 Large Data — Modo RPS

Corrida representativa: 100 RPS / 60s / Ramp-up 10s

image

⚠️ A 100 RPS con bulk inserts, el connection pool de Prisma comenzó a saturarse (error P2024). NestJS perdió ~15-18% de requests. Go procesó el 100% sin errores.

A 200 RPS, NestJS cayó al ~50% de success rate. A 300 RPS, al ~25-30%. Go aguantó hasta ~92% con SLOW SQL ocasional (~337ms).


🔴 Large Data — Modo Paralelo

Corrida representativa: 10 vUs / Ramp-up 5s / Duración 60s

image

📌 Con baja concurrencia, ambos sobreviven bien. A 50 vUs, la latencia de NestJS llega a ~550ms en P95. Go mantiene ~320ms. La diferencia en bulk operations bajo presión es donde Protobuf + Go marca la mayor distancia.


⚠️ Errores que encontré (y qué nos dicen)

Durante las pruebas de Large Data no todo salió perfecto. Estos son los errores registrados:

image

Conclusión de los errores: el problema no es Go vs NestJS, es que Prisma tiene un modelo de connection pool menos eficiente que pgx/GORM bajo carga concurrente pesada. Go no tuvo errores de pool en ninguna corrida estable.


🤔 ¿Cuándo cambia la ecuación?

Este es el punto central que quería explorar. Los datos muestran que no hay una respuesta única.

Cuando NestJS es suficiente (y la respuesta correcta)

  • Operaciones de negocio estándar, CRUD, APIs REST institucionales

  • Small payloads con carga moderada (< 300 RPS, < 100 vUs)

  • Equipos pequeños con roadmap de producto intenso — la DX de TypeScript/NestJS gana

  • MVPs, startups que están validando — no hay razón para el overhead de Go

  • Proyectos donde el equipo no tiene experiencia en Go (y no hay presupuesto para adquirirla)

Cuando Go empieza a justificarse

  • Bulk operations a escala (inserts masivos, streaming, ETL)

  • Ingesta de datos en tiempo real donde los picos del GC de Node.js son problemáticos

  • Servicios con SLAs muy estrictos en p99 (Go tiene pausas de GC mucho más predecibles)

  • Sistemas que esperan escalar a miles de conexiones concurrentes sin redimensionar infraestructura

  • El equipo ya tiene Go developers o hay presupuesto/tiempo para formarlos

El argumento de negocio (el más importante)

Go tiene costos reales que hay que reconocer:

  • Curva de aprendizaje alta: concurrencia con goroutines, gestión de errores explícita, sin genéricos maduros hasta hace poco, ecosistema más pequeño

  • Hiring más caro y difícil: Go developers son menos comunes que TypeScript developers

  • Más código para hacer lo mismo: lo que NestJS hace en un decorator, en Go son 50 líneas

¿Cuándo tiene sentido asumir ese costo? Cuando el problema de rendimiento es real y documentado, no hipotético. La regla es simple: medir primero, optimizar después. Si NestJS está sobreviviendo bien y el negocio crece, no hay urgencia. Si los logs empiezan a mostrar P2024, timeouts y degradación de p99 bajo carga, ahí es donde los datos de este benchmark se vuelven útiles.


⚖️ Tabla de Decisión

image


🏆 Conclusión

Los datos apuntan a un modelo híbrido como la arquitectura más pragmática:

  • La capa de alto tráfico, concurrencia y serialización: Go

  • La lógica de negocio, reglas de dominio, integraciones: NestJS

  • Los conectas por gRPC, y cada uno hace lo que mejor sabe hacer

Pero si hay algo que me llevo de este benchmark es que la clave no es qué tecnología es mejor, sino entender cuándo el costo de adoptar una nueva tecnología se justifica con el problema que estás resolviendo. Go no es una herramienta mágica. NestJS tampoco tiene un techo tan bajo como a veces se dice.

Los datos están. La decisión siempre depende del contexto.


💻 El Código Fuente

He publicado todo el código (NestJS, Go, Next.js Dashboard y Docker Compose) para que puedas ejecutar el benchmark en tu propia máquina.

🔗 GITHUB LINK


💌 Agradecimientos Especiales

A una chica que, sin saberlo, me empujó a seguir creando y programando en mi tiempo libre. A quien alguna vez fue mi chispa: para “YLP”, con gratitud… y con cicatrices que también enseñan.


Si el contenido te resulta útil o te ayuda a tomar mejores decisiones técnicas, lo aprecio. ☕️

Подобається цей допис?

Купити для Tomás Alegre каву

Більше від Tomás Alegre

КонфіденційністьУмовиПоскаржитись