0Pricing
Node.js Backend Development Bootcamp · Lesson

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 ctx parameter.
  • One missed hand-off and a downstream call loses context.
  • Library code you don't own can't receive your ctx at 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

  1. Structured Logging with Correlation IDs
  2. Distributed Tracing with OpenTelemetry Spans
  3. Exposing Application Metrics and the RED Method
  4. Context Propagation with AsyncLocalStorage
← Back to Node.js Backend Development Bootcamp