DEV Community

Cover image for Node.js: el runtime que cambió cómo pensamos el backend
Juan Torchia
Juan Torchia Subscriber

Posted on • Originally published at juanchi.dev

Node.js: el runtime que cambió cómo pensamos el backend

Corría 2012 y yo estaba metido hasta las orejas en servidores Linux, administrando stacks LAMP que respondían lento bajo carga. Un colega me pasó un benchmark: un servidor Node.js manejando 10.000 conexiones concurrentes con un proceso que consumía menos memoria que un Apache con 500. Lo miré tres veces. Pensé que era mentira. No era mentira.

En ese momento no lo adopté — seguí con mi mundo de infraestructura y Java. Pero la semilla quedó. Cuando en 2021 hice el pivot definitivo al desarrollo de software, Node estaba en todos lados. Y cuando lo entendí de verdad — no solo cómo usarlo sino por qué funciona así — me cayó la ficha de por qué había generado tanto ruido.

Este es el post #9 de la serie Awesome Curated: The Tools, donde analizo herramientas que pasan el filtro de nuestro sistema de curación automático. Node.js apareció referenciado desde la lista awesome-nodejs de Sindre Sorhus — que por sí sola es un universo — y cruzó con señal en 4 awesome lists independientes. Eso no pasa por casualidad.

Qué hace

Node.js es un runtime de JavaScript construido sobre el motor V8 de Chrome, pero eso es la descripción técnica aburrida. Lo que lo hace especial es el event loop no-bloqueante. En un servidor web tradicional, cada request que llega espera: espera que la base de datos responda, espera que el disco lea un archivo, espera que la red devuelva algo. Mientras espera, ese hilo está bloqueado, sin hacer nada útil. Multiplicá eso por miles de conexiones y entendés por qué necesitabas 64GB de RAM para un servidor decente.

Node invierte el modelo. Cuando hacés una operación I/O, Node registra un callback y sigue adelante. Cuando el disco termina de leer, cuando la DB responde, cuando el socket tiene datos — Node lo sabe y ejecuta lo que sigue. Un solo hilo manejando miles de operaciones en vuelo simultáneamente. No es magia, es un modelo mental diferente.

// El modelo tradicional (bloqueante): esperás en cada paso
// El modelo Node: registrás lo que querés que pase CUANDO algo esté listo

const fs = require('fs');
const http = require('http');

const server = http.createServer((req, res) => {
  // Esto NO bloquea el event loop
  // Node sigue atendiendo otras requests mientras el disco lee
  fs.readFile('./data.json', 'utf8', (err, data) => {
    if (err) {
      res.writeHead(500);
      res.end('Algo explotó');
      return;
    }
    // Recién acá respondemos, cuando el dato está disponible
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(data);
  });
});

server.listen(3000, () => {
  console.log('Escuchando en puerto 3000');
});
Enter fullscreen mode Exit fullscreen mode

Hoy la sintaxis moderna con async/await hace esto mucho más legible:

const fs = require('fs').promises;
const http = require('http');

const server = http.createServer(async (req, res) => {
  try {
    // Await no bloquea el event loop — libera el hilo mientras espera
    // Otros requests siguen siendo procesados en paralelo
    const data = await fs.readFile('./data.json', 'utf8');

    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(data);
  } catch (err) {
    res.writeHead(500);
    res.end(JSON.stringify({ error: 'No se pudo leer el archivo' }));
  }
});

server.listen(3000);
Enter fullscreen mode Exit fullscreen mode

El ecosistema npm es otro animal completamente. Más de 2 millones de paquetes. Es tanto una fortaleza absurda como un vector de quilombos de seguridad (left-pad, event-stream, los fantasmas del pasado). Pero el punto es que para casi cualquier cosa que necesitás, existe una librería. Podés ver el repositorio oficial acá y la awesome-nodejs de Sindre Sorhus acá — esa segunda URL es prácticamente un mapa del ecosistema completo.

Por qué está en la lista

Cuatro awesome lists independientes señalando Node.js es consenso de comunidad, no hype. Y tiene sentido: Node resolvió un problema real que tenía el desarrollo backend pre-2009 — la C10K problem, la dificultad de manejar 10.000 conexiones concurrentes con servidores tradicionales. Ryan Dahl no inventó el event loop, pero tomó una idea que existía en Nginx y la puso en manos de developers JavaScript que ya eran millones.

El unlock más importante fue unificar el lenguaje. Antes de Node, si eras dev web, sabías JavaScript en el browser y algo más (PHP, Ruby, Java) en el server. Con Node, el mismo lenguaje, los mismos paradigmas, el mismo equipo. Eso tuvo un impacto organizacional enorme que todavía se siente hoy en el mercado laboral.

Comparado con alternativas contemporáneas: Go gana en raw performance y simplicidad del modelo de concurrencia. Python con FastAPI o Django es más legible para muchos casos. Java con Spring Boot (mi mundo actual) tiene una madurez y tooling empresarial que Node todavía está construyendo. Pero ninguno de ellos tiene el ecosistema npm, ninguno tiene la barrera de entrada tan baja para alguien que ya sabe JavaScript, y ninguno movió tan rápido el mercado de herramientas de desarrollo — Webpack, Babel, ESLint, Prettier, todos corren sobre Node.

Cuándo NO usarlo

Si tenés CPU-bound workloads — procesamiento de imágenes, criptografía pesada, machine learning, compilación — Node te va a defraudar. El event loop es brillante para I/O concurrente pero el single thread se convierte en cuello de botella cuando hay cómputo intensivo. Los Worker Threads mitigan esto, pero en ese punto ya estás peleando contra el diseño del runtime. Para eso, Python con multiprocessing, Go, o Java son opciones más naturales.

Los memory leaks son más frecuentes y más difíciles de debuggear que en lenguajes compilados. El garbage collector de V8 es bueno, pero si no entendés el modelo de closures y referencias circulares, vas a ver procesos que crecen de memoria sin parar hasta que explotan en producción a las 3 de la mañana. Hablo por experiencia propia. También: si tu equipo no tiene experiencia sólida con programación asíncrona, el callback hell y los errores sutiles de async/await pueden generar código muy difícil de mantener. En esos casos, un framework con más estructura opinionada como Spring Boot o Django puede ser más sano a largo plazo.

Cierre

Node.js es una de esas herramientas que cambió el ecosistema de forma permanente. No porque sea perfecta — no lo es — sino porque llegó en el momento justo con la idea correcta y arrastró a millones de developers con ella. Treinta años viendo tecnología me enseñaron a distinguir el hype que se desvanece del cambio real. Node es lo segundo.

Si este post te resultó útil, la serie Awesome Curated: The Tools tiene 8 posts más donde analizo herramientas con el mismo criterio. Desde criptografía con Themis hasta monitoreo de red con Sniffnet — cada una pasó el mismo filtro de curación antes de llegar acá. El próximo también.


Este artículo fue publicado originalmente en juanchi.dev

Top comments (0)