En el desarrollo moderno de aplicaciones Node.js, especialmente aquellas construidas con frameworks como Express o NestJS, surge una necesidad recurrente: mantener un contexto único por petición que pueda ser accedido desde cualquier capa de la aplicación —servicios, loggers, repositorios— sin tener que pasar explícitamente un objeto a través de cada función. Este problema, aparentemente simple, se vuelve complejo cuando trabajamos con operaciones asíncronas como promesas, temporizadores o llamadas a bases de datos. Las soluciones tradicionales, como una variable global o un singleton, fallan estrepitosamente bajo concurrencia, ya que distintas peticiones compartirían el mismo estado, provocando corrupción de datos y comportamientos impredecibles. La alternativa de pasar un objeto context manualmente a cada función es tediosa, genera acoplamiento y dificulta el mantenimiento del código. Aquí es donde entra en juego AsyncLocalStorage, una API nativa de Node.js (disponible desde la versión 16.4 sin necesidad de paquetes externos) que resuelve elegantemente este desafío al proporcionar un almacenamiento aislado por cadena de ejecución asíncrona.
AsyncLocalStorage pertenece al módulo node:async_hooks y su funcionamiento es sorprendentemente simple pero potente. Cada vez que se inicia una nueva petición —por ejemplo, en un middleware de Express o un interceptor de NestJS—, llamamos a als.run(store, callback), donde store es un objeto con los datos de contexto que queremos conservar (como un requestId o userId). Dentro de ese callback se ejecuta toda la lógica de la petición, incluyendo cualquier operación asíncrona posterior. Node.js enlaza el almacén al recurso asíncrono que se crea en ese momento, de modo que cualquier await, setTimeout, Promise.then() o incluso un callback que se programe dentro de esa cadena heredará automáticamente el mismo contexto. Si una segunda petición llega mientras tanto, su propio als.run() creará un almacén independiente, garantizando un aislamiento total. De esta forma, logramos un patrón de contexto de petición sin necesidad de inyectar dependencias ni ensuciar las firmas de las funciones.
Desde un punto de vista práctico, la implementación en Express es directa: creamos un middleware que genera un requestId (por ejemplo, a partir de la cabecera x-request-id o generando un UUID), lo almacena en un objeto, establece la cabecera de respuesta correspondiente, y luego invoca requestContext.run(store, next). Cualquier función que se ejecute dentro de ese flujo —incluyendo un logger, un servicio de base de datos o incluso una librería externa— puede recuperar el requestId mediante requestContext.getStore(). Para evitar errores, es recomendable usar encadenamiento opcional (?.requestId) o un valor por defecto, ya que fuera de run() el método devuelve undefined. En NestJS, la mecánica es idéntica pero se implementa como un interceptor global que envuelve el manejador de la ruta con als.run(). Además, podemos crear decoradores de parámetros como @RequestId() para extraer el campo directamente en los controladores, manteniendo un código limpio y desacoplado. Existen librerías como nestjs-cls que ofrecen tipado y funcionalidades adicionales, pero la API nativa es suficiente para la mayoría de los casos.
Un aspecto crucial que a menudo se pasa por alto es el límite de la petición: siempre debemos llamar a als.run() en el punto de entrada, nunca dentro de un constructor de un servicio singleton, porque ese constructor se ejecuta una sola vez y el contexto se perdería. Tampoco funcionará si programamos un callback antes de run() o desde otra petición, ya que el enlace al recurso asíncrono es específico de la cadena. Por último, hay que tener presente que los worker threads y los procesos cluster usan sus propias instancias de AsyncLocalStorage, por lo que el contexto no se comparte entre ellos. A pesar de estas limitaciones, la API es extraordinariamente útil para casos como el logging estructurado (donde cada línea de log lleva el requestId sin necesidad de pasarlo manualmente), la traza distribuida (OpenTelemetry usa internamente AsyncLocalStorage para propagar el contexto entre microservicios) o la gestión de transacciones de base de datos a nivel de petición (como hace typeorm-transactional).
En el contexto empresarial, dominar esta técnica permite construir aplicaciones más robustas, escalables y mantenibles. En Q2BSTUDIO, empresa especializada en el desarrollo de aplicaciones a medida, integramos patrones como el contexto de petición con AsyncLocalStorage en nuestros proyectos Node.js para garantizar que cada transacción quede correctamente trazada, facilitando la depuración y la auditoría. Esto es especialmente relevante cuando trabajamos con software a medida que debe operar bajo alta concurrencia, como plataformas de comercio electrónico o sistemas de gestión interna. Además, combinamos estas arquitecturas con servicios cloud aws y azure para desplegar aplicaciones resilientes, y con servicios inteligencia de negocio y power bi para ofrecer dashboards en tiempo real basados en los datos generados por cada petición. El contexto de petición también es fundamental en soluciones de inteligencia artificial y ia para empresas, donde cada solicitud a un modelo debe conservar su propio historial o sesión; en nuestra práctica, usamos agentes IA que, gracias a AsyncLocalStorage, pueden mantener el estado de la conversación sin conflictos entre usuarios concurrentes. Asimismo, la capacidad de auditar cada petición con un identificador único refuerza las estrategias de ciberseguridad, ya que facilita la detección de anomalías y la implementación de pentesting controlado.
Para ilustrar su aplicación concreta, en Q2BSTUDIO hemos desarrollado un microservicio de autenticación donde cada petición inyecta en el contexto el userId y un sessionToken. Luego, los servicios de autorización y los loggers acceden a estos datos sin necesidad de pasarlos como argumento, lo que simplificó significativamente el código y redujo errores. Un patrón similar lo aplicamos en proyectos de automatización de procesos, donde el contexto transporta el identificador del workflow activo. Si desea explorar cómo implementar estas soluciones en su organización, le invitamos a conocer nuestros servicios de desarrollo de aplicaciones a medida o descubrir cómo integramos inteligencia artificial para empresas con agentes IA avanzados. AsyncLocalStorage no solo es una herramienta técnica: es un habilitador de arquitecturas limpias y seguras que permiten escalar sin perder el control del estado. Dominarlo es, hoy en día, una habilidad esencial para cualquier desarrollador backend Node.js que aspire a construir aplicaciones profesionales.

.jpg)
.jpg)

.jpg)
.jpg)