Context Propagation with AsyncLocalStorage
Carry request-scoped state across async boundaries without prop drilling using AsyncLocalStorage.
The Prop-Drilling Problem
In a backend service, request-scoped data such as a request ID, the authenticated user, or a tenant ID is needed deep inside your call stack: in repositories, loggers, and outbound HTTP clients.
The naive fix is prop drilling — threading a ctx argument through every function:
- Every function signature gets polluted with a
ctxparameter. - One missed hand-off and a downstream call loses context.
- Library code you don't own can't receive your
ctxat all.
We need a way to carry per-request state implicitly, surviving every await and callback. That is exactly what AsyncLocalStorage provides.
async function handler(ctx, req) {
const user = await loadUser(ctx, req.userId);
return await renderPage(ctx, user);
}
async function loadUser(ctx, id) {
log(ctx, 'loading user'); // ctx passed again
return await db.find(ctx, id); // and again...
}
// Every layer must accept and forward ctx by hand.What AsyncLocalStorage Is
AsyncLocalStorage lives in the built-in node:async_hooks module. Think of it as thread-local storage for the async world: a store that stays attached to a logical chain of asynchronous operations.
You call als.run(store, callback) to establish a store, then anywhere inside that callback — no matter how many awaits, Promise chains, setTimeouts, or event emitters deep — als.getStore() returns the same store.
- Each concurrent request gets its own isolated store.
- No globals, no race conditions between requests.
- Powered by Node's async context tracking under the hood.
import { AsyncLocalStorage } from 'node:async_hooks';
const als = new AsyncLocalStorage();
als.run({ requestId: 'abc-123' }, () => {
setTimeout(() => {
const store = als.getStore();
console.log(store.requestId); // 'abc-123'
}, 10);
});All lessons in this course
- Structured Logging with Correlation IDs
- Distributed Tracing with OpenTelemetry Spans
- Exposing Application Metrics and the RED Method
- Context Propagation with AsyncLocalStorage