Presentación
Node.js es un runtime JavaScript open source y multiplataforma que permite ejecutar JavaScript fuera del navegador. Se utiliza especialmente para construir servidores Web, API, herramientas de línea de comandos, scripts de automatización, servicios de red e infraestructuras de desarrollo.
El runtime se basa en V8, el motor JavaScript utilizado también por Chromium. Node.js añade un conjunto importante de API del sistema que no existen en el propio lenguaje JavaScript: acceso a archivos, red TCP y HTTP, procesos, sistema operativo, criptografía, streams, workers o ejecución de programas externos.
Node.js es especialmente conocido por su modelo asíncrono y orientado a eventos. En lugar de asociar sistemáticamente un thread a cada conexión de red, se apoya en una event loop y en libuv para orquestar numerosas operaciones concurrentes con relativamente pocos threads.
Esta arquitectura resulta especialmente adecuada para aplicaciones que realizan muchas operaciones de entrada/salida: servidores HTTP, API, WebSocket, acceso de red, archivos o comunicaciones con bases de datos. Los cálculos CPU muy pesados requieren, en cambio, una atención particular para no bloquear la event loop.
Node.js también desempeña un papel central en el ecosistema del desarrollo Web moderno. Numerosos frameworks, bundlers, compiladores, generadores de sitios y herramientas front-end se ejecutan sobre Node.js, incluso cuando la aplicación final debe funcionar dentro de un navegador.
El runtime admite los dos principales sistemas de módulos del ecosistema JavaScript: ECMAScript Modules — ESM, que utilizan import y export, y CommonJS, que históricamente utiliza require() y module.exports.
Su ecosistema está estrechamente relacionado con npm, que permite instalar y publicar packages JavaScript. La distribución Current verificada, Node.js 26.8.2, se ofrece actualmente con npm 11.19.1.
Node.js también dispone actualmente de numerosas funciones que anteriormente solo proporcionaban bibliotecas externas: fetch(), WebSocket, Web Streams, test runner, gestión de permisos, soporte ligero de TypeScript e incluso un módulo SQLite integrado todavía en proceso de estabilización.
Durante esta verificación, la última versión publicada es Node.js 26.8.2 — Current. La última versión LTS es Node.js 24.21.0 — Krypton. Para aplicaciones en producción, el proyecto Node.js recomienda utilizar una rama LTS todavía compatible en lugar de la rama Current.
Funcionalidades
Un runtime JavaScript construido alrededor de V8
Node.js utiliza V8 para parsear, compilar y ejecutar código JavaScript.
El motor admite las funcionalidades modernas del lenguaje ECMAScript y evoluciona a medida que Node.js adopta nuevas versiones de V8.
Node.js 26 utiliza especialmente V8 14.6 durante el lanzamiento de su rama mayor y activa por defecto determinadas novedades del lenguaje como Temporal, la nueva API JavaScript destinada a gestionar mejor fechas, horas, zonas horarias y duraciones.
El papel de Node.js va, sin embargo, más allá del motor JavaScript.
Añade las API necesarias para convertir JavaScript en un verdadero entorno de ejecución de sistema: archivos, red, procesos, criptografía, threads, terminal y muchos otros servicios.
Event loop y modelo asíncrono
La arquitectura de Node.js se basa principalmente en una event loop encargada de ejecutar el código JavaScript y procesar los callbacks asociados a los eventos.
Por tanto, las operaciones largas de entrada/salida no necesitan necesariamente bloquear este bucle.
Node.js se apoya especialmente en libuv, que proporciona la event loop y una abstracción multiplataforma para numerosas operaciones del sistema.
Determinadas tareas también utilizan un Worker Pool, por ejemplo para varias operaciones relacionadas con el sistema de archivos o la criptografía.
Esta arquitectura permite a un mismo proceso Node.js gestionar un gran número de conexiones simultáneas siempre que cada tarea JavaScript siga siendo relativamente corta.
No obstante, incluye una regla importante: un cálculo CPU demasiado largo ejecutado directamente en la event loop puede ralentizar todo el servidor.
Por tanto, el código debe evitar tratamientos síncronos costosos dentro de un servidor muy solicitado o desplazar los cálculos importantes hacia workers o procesos adecuados.
Servidores HTTP y red integrados
Node.js proporciona directamente los módulos necesarios para crear servidores de red.
El módulo node:http permite construir un servidor HTTP sin instalar un framework externo.
node:https añade soporte TLS para HTTPS.
El runtime también incluye módulos de más bajo nivel para TCP, UDP, DNS o TLS.
Frameworks como Express, Fastify o NestJS pueden después proporcionar una arquitectura más cómoda sobre estas primitivas.
Esta capacidad para gestionar directamente la red explica en gran parte el éxito histórico de Node.js en el servidor.
fetch(), WebSocket y API cercanas al navegador
Node.js ha integrado progresivamente varias Web APIs disponibles también en los navegadores.
fetch() es actualmente estable y permite realizar peticiones HTTP sin instalar sistemáticamente una biblioteca adicional.
Su implementación se basa en Undici, el cliente HTTP desarrollado para el ecosistema Node.js.
El runtime también proporciona objetos compatibles con Web APIs como:
Headers;Request;Response;FormData;AbortController;URL;URLSearchParams;- Web Streams.
WebSocket también está disponible de forma nativa y es estable desde Node.js 22.4.
Este acercamiento a los estándares Web facilita compartir determinadas partes del código entre navegador y servidor, aunque ambos entornos siguen conservando numerosas diferencias.
Sistema de archivos, rutas e información del sistema
Node.js puede acceder directamente al sistema de archivos mediante node:fs.
Permite especialmente:
- leer y escribir archivos;
- crear o eliminar carpetas;
- recuperar metadatos;
- trabajar con permisos;
- vigilar determinados cambios;
- crear streams de lectura o escritura.
La mayoría de las operaciones importantes disponen de variantes asíncronas.
node:fs/promises proporciona una interfaz basada en Promise y async/await.
node:path permite manipular rutas sin depender manualmente de las diferencias de separadores entre Windows y los sistemas Unix.
Otros módulos integrados ofrecen acceso al sistema operativo, variables de entorno, argumentos del proceso e información de ejecución.
ECMAScript Modules y CommonJS
Node.js dispone actualmente de dos sistemas de módulos principales.
CommonJS constituye el modelo histórico de Node.js, con require() y module.exports.
ECMAScript Modules corresponden al estándar JavaScript moderno con import y export.
Un proyecto puede indicar su formato especialmente mediante:
- la extensión
.mjspara ESM; - la extensión
.cjspara CommonJS; - el campo
"type": "module"o"type": "commonjs"dentro depackage.json.
Node.js proporciona actualmente una interoperabilidad importante entre ambos sistemas.
Los nuevos proyectos pueden por tanto utilizar directamente módulos ES mientras siguen aprovechando gran parte del ecosistema histórico CommonJS.
Esta convivencia puede, sin embargo, provocar determinados problemas de configuración, especialmente en packages que deben funcionar simultáneamente con varias herramientas o versiones de Node.js.
npm y gestión de packages
Node.js está estrechamente asociado a npm, el gestor de packages histórico de su ecosistema.
Un proyecto Node.js utiliza generalmente un archivo package.json para declarar:
- nombre y versión;
- dependencias;
- scripts;
- tipo de módulos;
- restricciones de versiones;
- metadatos del package.
npm install recupera las dependencias necesarias.
Los scripts npm pueden después automatizar tests, builds, linters, migraciones u otros comandos del proyecto.
El ecosistema npm contiene una cantidad extremadamente importante de packages que cubren prácticamente todos los ámbitos del desarrollo JavaScript.
Esta riqueza constituye una gran fortaleza de Node.js, pero también implica vigilar las dependencias, sus licencias, su mantenimiento y sus vulnerabilidades.
Ejecución nativa ligera de TypeScript
Node.js dispone actualmente de soporte nativo de TypeScript mediante type stripping.
Esta función es estable en las versiones recientes y está activada por defecto.
Node.js puede ejecutar directamente archivos TypeScript que utilicen únicamente sintaxis de tipos que pueda eliminarse sin generar nuevo JavaScript.
El runtime sustituye esencialmente las anotaciones de tipos por espacios y después ejecuta el JavaScript restante.
Es importante comprender los límites de esta función:
- Node.js no verifica los tipos;
tsconfig.jsones ignorado por este modo;- los alias
pathsde TypeScript no se transforman; - los archivos
.tsxno son compatibles; - determinadas construcciones que requieren transformación JavaScript, como los
enum, no funcionan con simple type stripping; - los imports de tipos deben utilizar correctamente
import type.
Para beneficiarse de todas las funcionalidades de TypeScript, la verificación de tipos y la configuración tsconfig, sigue siendo preferible utilizar el compilador TypeScript o una herramienta adecuada como tsx.
El soporte integrado de Node.js busca por tanto principalmente ejecutar TypeScript ligero de forma sencilla, no sustituir toda la toolchain TypeScript.
Streams para tratar los datos progresivamente
Los streams constituyen una primitiva central de Node.js.
En lugar de cargar completamente un archivo o respuesta de red en memoria, una aplicación puede tratar los datos progresivamente.
Node.js distingue principalmente:
Readable;Writable;Duplex;Transform.
Un archivo leído desde el disco, una petición HTTP, una respuesta del servidor, un socket TCP o la salida estándar pueden representarse como streams.
Esta arquitectura resulta especialmente útil para:
- archivos grandes;
- uploads;
- descargas;
- compresión;
- proxies de red;
- transformación de datos.
stream.pipeline() facilita encadenar varias etapas gestionando correctamente errores y cierre de streams.
Node.js también admite interoperabilidad con los Web Streams utilizados por los estándares Web modernos.
Worker Threads para cálculos CPU
El módulo node:worker_threads permite ejecutar JavaScript en paralelo dentro de varios threads.
Los workers son principalmente útiles para operaciones CPU-intensive.
Pueden compartir determinados datos mediante SharedArrayBuffer o transferir objetos ArrayBuffer.
Para operaciones convencionales de entrada/salida, las API asíncronas nativas de Node.js suelen ser más adecuadas que crear workers.
El uso típico consiste por tanto en reservar la event loop para las operaciones de red y desplazar determinados cálculos costosos hacia un pool de Worker Threads.
Procesos hijos y ejecución paralela
Node.js también puede lanzar otros procesos mediante node:child_process.
Esta API permite especialmente:
- ejecutar un comando del sistema;
- lanzar un programa externo;
- crear un proceso Node.js hijo;
- intercambiar mensajes entre procesos.
Los procesos proporcionan un aislamiento mayor que Worker Threads, pero generalmente consumen más recursos.
El módulo histórico cluster también permite utilizar varios procesos Node.js