Course contentsShow
← Node.js
Lesson 262 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Managing Global Async Contexts

You will use AsyncLocalStorage to track request-scoped state throughout deep asynchronous call chains.

In this lesson, you will learn how to maintain request-specific information—like user IDs or transaction tokens—across complex, deeply nested asynchronous call chains without manually passing arguments through every single function.

The Problem: Passing "Prop Drilling"

When your application processes a web request, you often need to access data (like an authentication token) inside deep helper functions. Normally, you would have to pass this variable as a parameter to every function in the chain: doWork(token), then process(token), then save(token). This creates messy code and limits your flexibility.

The Solution: AsyncLocalStorage

Node.js provides a tool called AsyncLocalStorage that allows you to store state in a "global" container that is magically scoped to the current asynchronous execution flow. Think of it like a private scratchpad that follows your request wherever it goes, even if it jumps across setTimeout, database calls, or file I/O operations.

Here is how you use it:

const { AsyncLocalStorage } = require('async_hooks');
const asyncLocalStorage = new AsyncLocalStorage();

function logWithContext() {
  // Retrieve the value anywhere in the chain
  const store = asyncLocalStorage.getStore();
  console.log(`Current Request ID: ${store.requestId}`);
}

function processRequest(req, res) {
  const context = { requestId: req.headers['x-request-id'] };
  
  // Wrap the call chain in .run()
  asyncLocalStorage.run(context, () => {
    // Any function called here can access the context
    logWithContext();
  });
}

How it Works

When you call asyncLocalStorage.run(context, callback), Node.js attaches that context to the current execution thread. Because Node’s event loop tracks asynchronous resources, it "remembers" this context even when your code waits for a database to return a result or a timer to finish. Deep inside your business logic, you simply call getStore() to grab the data you need without ever having to pass it as an argument. It keeps your function signatures clean and your data flow predictable across your entire application.

Key Takeaway: AsyncLocalStorage allows you to share state across deep async operations without cluttering your code with passed arguments, effectively creating "execution-scoped global variables."