23 puntos por GN⁺ 2025-08-04 | 3 comentarios | Compartir por WhatsApp
  • El entorno de desarrollo de Node.js ha atravesado en los últimos años cambios fundamentales en términos de alta compatibilidad con los estándares web y fortalecimiento de sus capacidades integradas
  • Con la adopción de sistemas modernos de módulos y patrones asíncronos como ESM (ES Modules), el prefijo node: y top-level await, ahora es posible escribir código más intuitivo y seguro
  • Fetch API, AbortController y Web Streams reducen la dependencia de bibliotecas externas y permiten cubrir muchas funciones con APIs integradas
  • Herramientas de desarrollo integradas como test runner, modo Watch y soporte para archivos de entorno mejoran mucho la comodidad de trabajo y la productividad
  • Con el refuerzo de la infraestructura de seguridad y despliegue, que incluso permite control de permisos, canales de diagnóstico y distribución como ejecutable único, Node.js moderno está evolucionando hacia una plataforma profesional y de propósito general

Cambios y evolución de Node.js

  • Node.js está dejando atrás su estructura inicial centrada en callbacks y CommonJS para convertirse hoy en un entorno de desarrollo más estandarizado
  • Este cambio no es solo superficial, sino una transformación del paradigma general de desarrollo de JavaScript del lado del servidor

1. Sistema de módulos: estandarización de ES Modules

  • Aunque CommonJS fue durante mucho tiempo el enfoque usado en Node.js, tiene limitaciones como el análisis estático, el tree shaking y la falta de alineación con los estándares web
  • El enfoque ESM (ES Modules) se ha consolidado como el nuevo estándar de Node.js
    • Uso de la sintaxis import y export
    • Se introdujo el prefijo node: para diferenciar explícitamente los módulos integrados
      • Ejemplo: import { readFile } from 'node:fs/promises'
      • La distinción entre módulos integrados y paquetes de npm queda más clara
  • Con soporte para top-level await, ahora se puede usar await en el nivel superior del módulo
    • Ya no hace falta envolverlo con una función asíncrona autoejecutable
    • El código se vuelve más lineal y fácil de entender

2. APIs web integradas: menos dependencias externas

  • La Fetch API viene integrada en Node.js, lo que permite hacer solicitudes HTTP sin dependencias externas como Axios o node-fetch
  • Fetch soporta de forma nativa tiempo de espera y cancelación (AbortSignal.timeout())
    • Permite un manejo de errores consistente sin bibliotecas adicionales para timeout
  • Con AbortController se pueden implementar patrones de cancelación en distintos trabajos asíncronos como archivos y red
    • Ofrece una forma estandarizada de responder a interrupciones del usuario o a tiempos de espera

3. Pruebas integradas: un entorno de testing profesional

  • Sin necesidad de frameworks externos como Jest o Mocha, el test runner integrado de Node.js puede cubrir la mayoría de los requerimientos
    • Escritura de pruebas intuitiva con node:test y node:assert
  • Incluye funciones prácticas para desarrollo como modo Watch para pruebas y reportes de cobertura
    • Las pruebas se ejecutan automáticamente cada vez que se modifica el código
    • Node.js 20 o superior ofrece cobertura experimental

4. Patrones asíncronos evolucionados

  • Aunque async/await se usa ampliamente, en el Node.js moderno se enfatiza el uso de patrones de ejecución paralela y manejo más fino de errores
    • Trabajo en paralelo con Promise.all() y manejo de errores en un solo try/catch con información de contexto
  • El uso de AsyncIterator facilita el procesamiento secuencial de eventos y el control del flujo

5. Funciones avanzadas de streams y compatibilidad con estándares web

  • La API de streams ha ganado compatibilidad con el estándar web (Streams API)
    • Con Readable.fromWeb y Readable.toWeb es posible convertir streams entre Node.js y el navegador
  • La función pipeline (basada en Promise) permite construir pipelines de streams de forma intuitiva y segura

6. Worker Threads: procesamiento paralelo para tareas intensivas de CPU

  • Con WorkerThreads es posible superar el límite del hilo único de JS y aprovechar múltiples núcleos
  • Permite realizar cálculos complejos o procesar grandes volúmenes de datos sin bloquear el bucle principal

7. Innovación en la experiencia de desarrollo

  • Con la bandera --watch se detectan cambios en el código y se reinicia automáticamente sin necesidad de nodemon
  • Con la bandera --env-file ya no hace falta dotenv, y se pueden usar variables de entorno de inmediato
  • La configuración del entorno de desarrollo se vuelve más simple y rápida

8. Seguridad y monitoreo de rendimiento integrados

  • Con el experimental Permission Model se pueden restringir permisos de la aplicación, como acceso a archivos o red
    • Favorece la implementación del principio de mínimo privilegio y el cumplimiento de seguridad
  • Con perf_hooks se puede medir rendimiento de forma integrada y analizar o registrar automáticamente tareas lentas

9. Modernización del despliegue y empaquetado

  • Con soporte para SEA (Single Executable Application), se puede distribuir Node.js y la aplicación como un único binario
    • Esto facilita el despliegue e instalación incluso en entornos sin Node.js preinstalado

10. Manejo moderno de errores y diagnóstico

  • Las clases de error estructuradas incluyen contexto rico e información de diagnóstico, y permiten entregar objetos de error consistentes
  • Con diagnostics_channel se pueden transmitir datos de diagnóstico personalizados basados en eventos y automatizar el monitoreo

11. Evolución en la resolución de módulos y la gestión de paquetes

  • Con Import Maps se pueden gestionar rutas internas dentro de un namespace separado
    • Aumenta la facilidad para separar módulos internos y refactorizar
  • Con import dinámico es posible cargar código en tiempo de ejecución y hacer code splitting según el entorno o la configuración

Resumen clave y perspectiva futura

  • En Node.js son clave el cumplimiento de estándares web, el máximo aprovechamiento de herramientas integradas y la adopción de patrones asíncronos modernos
  • Con Worker Threads para procesamiento paralelo de alto rendimiento y funciones de diagnóstico y seguridad, sigue evolucionando como una plataforma para uso profesional
  • Funciones nuevas como el despliegue como ejecutable único y los namespaces de módulos aumentan mucho la facilidad operativa
  • Estos patrones pueden adoptarse de manera gradual manteniendo compatibilidad con código existente
  • Incluso después de 2025, Node.js seguirá evolucionando, y estos patrones modernos presentados aquí apuntan a convertirse en la base de aplicaciones orientadas al futuro

3 comentarios

 
sanori 2025-08-07

Empecé a crear un proyecto con Deno pensando "vaya, hasta esto se puede hacer", pero parece que node.js también está cambiando de forma similar.

 
dnltmdwhd 2025-08-05

Oh, ahora ya no hace falta usar axios, se puede usar fetch directamente.

 
GN⁺ 2025-08-04
Comentarios de Hacker News
  • El cambio más grande no es ESM sino que Node ahora trae fetch y AbortController integrados; pude quitar axios y node-fetch, reducir el tamaño de los bundles de Lambda y también recortar la latencia de cold start en unos 100 ms. Si eres de los que por costumbre hacen npm i axios, la versión de Node de 2025 es el momento de dejarlo.
    • Prefiero ts-rest en todo el stack para cubrir tanto llamadas a API como validación; entre las librerías basadas en zod/JSON Schema es la más ligera y al mismo tiempo ofrece una seguridad de tipos robusta. También te deja conectar el cliente HTTP que quieras usar (en Bun y en el motor de Node elijo fastify), y aunque tiene algo de overhead, vale totalmente la pena porque mueve la seguridad de tipos a la etapa de compilación. Me pregunto si alguien conoce una alternativa mejor o tiene otra opinión; revisé todo lo que pude encontrar y solo ts-rest logró combinar ligereza y seguridad de tipos.
    • No me convence tanto la sintaxis de fetch ni el trabajo extra de manejo de excepciones como await response.json; con axios todo se siente mucho más intuitivo. Incluso en el código de ejemplo, con axios puedes manejar simplemente response.data, mientras que con fetch tienes que revisar el status por tu cuenta y luego parsear el JSON, así que es más engorroso.
    • Como autor de librerías, para mí la adopción de ESM fue mucho más dura y dolorosa, pero aun así fue una mejora que valió la pena. fetch en sí es excelente, pero gracias a ESM obtuvimos muchísimas más cosas.
    • node fetch me parece mucho más fácil y simple que axios, así que lo prefiero. Ni sabía que todavía había gente usando axios.
    • Tengo muchísimas expectativas con Undici, la librería de requests integrada. Consulten el sitio oficial de undici.
  • Ahora ya se puede ejecutar limitando permisos de acceso al sistema de archivos o a la red de esta forma:
    # Ejemplo de restricción de acceso al sistema de archivos
    node --experimental-permission \
      --allow-fs-read=./data --allow-fs-write=./logs app.js
    
    # Ejemplo de restricción de red
    node --experimental-permission \
      --allow-net=api.example.com app.js
    
    Parece inspirado en Deno, y de verdad es una función excelente. Vean la documentación de permisos de Deno.
  • Ya es posible aplicar estilos al texto directamente sin instalar chalk ni picocolors:
    const { styleText } = require('node:util');
    
    Consulten la documentación oficial de styleText.
  • Me enteré de varias cosas que se pueden aplicar de inmediato:
    1. Node ahora trae testing integrado, así que ya no hace falta usar jest a la fuerza.
    2. Node también trae watch integrado, así que nodemon tampoco es necesario.
    • Aun así sigo prefiriendo jest, porque puedo usar jest-extended.
    • Creo que el sistema de testing integrado de Node tiene poca calidad; si lo usas unas semanas entiendes por qué, y aunque reportes issues, al equipo de Node no parece importarle demasiado.
  • Según Matteo Collina, node fetch usa internamente el fetch de undici; como tiene que crear WHATWG Web Streams, por naturaleza es más lento que el enfoque request de undici.
    YouTube donde lo menciona,
    blog sobre cómo funciona undici
    • Para quien tenga curiosidad, el benchmark se puede ver aquí. Probé hace poco en una MacBook Pro M3 Max tanto en local como en red: undici fue el mejor en local, pero en red Axios dio resultados más rápidos. No sé exactamente por qué, pero mi experiencia usando undici durante el último año y medio ha sido excelente. Se puede usar en producción con total estabilidad, aunque si quieres exprimir al máximo el rendimiento, sí hace falta pensar bien según cada contexto.
  • Gracias al transpiler nativo de TypeScript en Node, para quienes usan TS la complejidad baja bastante.
    • En realidad no transpila; solo elimina tipos, así que cosas como TS enum no funcionan bien.
    • Todavía le falta para uso real; no me preocupan los enum, pero ni siquiera deja hacer import de archivos locales sin extensión, y tampoco se pueden definir class properties en el constructor.
    • El flag --experimental-strip-types ya tampoco hace falta.
  • Muchas veces me entero de las nuevas funciones de esta manera, casi por accidente. Me da una sensación parecida a la del navegador, como de “eso es nuevo así que debe existir”. Cuando antes solo trabajaba con C#, me emocionaba mucho leer sobre nuevas funciones del lenguaje, pero hoy, como uso varios lenguajes a la vez, ya no es tan fácil seguirle el paso a uno solo. Casi todo lo aprendo al azar por blogs o por gente alrededor.
    • Como me interesan mucho las novedades de Node (V8), leo las release notes cada 2 o 3 meses para estar al tanto de funciones como estas. A veces también leo las propuestas de ECMA. Ojalá algún día sí entre el pipeline operator.
  • Llevaba tiempo alejado del ecosistema de Node y al volver me sorprendió ver cuántas funciones nuevas e interesantes hay. Creo que es resultado de que Deno y Bun movieron el mercado y empujaron al equipo de Node a esforzarse más.
  • Poco a poco Node se está volviendo un competidor nada fácil frente a Bun.js, Deno y otros. Esa competencia mutua es positiva para la evolución de los runtimes de JS.
    • Los cambios son lentos, pero firmes y bienvenidos. Aun así, sigo extrañando la función de shell $ de Bun; usar JS como si fuera scripting es realmente muy cómodo, y no quisiera tener dos runtimes al mismo tiempo en el servidor.
  • Igual que en los navegadores, creo que las nuevas funciones de Node se pueden dividir en dos tipos:
    1. tecnología totalmente nueva
    2. capas de “maquillaje” montadas sobre funciones que ya existen
      También es interesante ver a cuál de las dos les da más peso la gente.
    • Lo que para alguien es una “capa de maquillaje”, para otra persona puede ser usabilidad (ergonomics).