Glossary / Async context propagation
Async context propagation
Async context propagation carries request-scoped or operation-scoped metadata—such as a trace ID, tenant, locale, or security principal—across asynchronous boundaries. In JavaScript, ordinary lexical variables do not automatically become globally available to unrelated callbacks; runtimes provide context mechanisms, while explicit parameter passing remains the clearest and most portable option.
Context in Node.js
Node's AsyncLocalStorage associates a store with an asynchronous execution chain. run(store, callback) enters a context for work scheduled from the callback; APIs built on Node's async resource tracking propagate it through many promise, timer, and I/O boundaries.
import { AsyncLocalStorage } from 'node:async_hooks';
const requestContext = new AsyncLocalStorage();
function handleRequest(req) {
requestContext.run({ requestId: req.id }, async () => {
await loadData();
console.log(requestContext.getStore()?.requestId);
});
}
Propagation is not magic across every boundary. Custom thenables, native addons, callback APIs, worker threads, child processes, and message queues may require explicit context capture or serialization. Context does not automatically cross process or worker boundaries; include needed metadata in messages. Browser APIs have different mechanisms and no universal built-in equivalent for arbitrary application context.
Design risks
Ambient context can simplify logging and tracing, but hidden dependencies make functions harder to reason about, test, and reuse. Do not use it as an implicit authorization source without careful lifecycle and isolation guarantees. Avoid storing large mutable objects or request bodies; context can retain memory longer than expected. Clear or scope context at request boundaries and never let concurrent requests share a mutable store.
Engineering guidance
Prefer explicit arguments for business-critical dependencies. Use async context for cross-cutting observability metadata where reducing parameter threading is valuable. Test propagation through promises, timers, callbacks, and custom integrations. Verify isolation under concurrent requests and ensure spawned background work either intentionally retains the context or starts a new one.
Interview questions
- What problem does async context solve? Making request-scoped metadata available across asynchronous callbacks without threading it through every function signature.
- Does it cross worker/process boundaries automatically? No; serialize required context in messages or establish a new context at the destination.
- Why can ambient context hurt design? It introduces hidden dependencies and can complicate tests, reuse, and lifecycle reasoning.
- How does Node implement the public pattern?
AsyncLocalStorageover async resource tracking. - What must be tested? Propagation, concurrent isolation, integrations, and whether detached work keeps or drops context intentionally.