courses.reviews - My new website for finding the best coding courses, with reviews & exclusive discounts. It's free!

Published
5 min read
Up to date

Trevor I. Lasn

Staff Engineer, EM & Entrepreneur

AsyncLocalStorage: Simplify Context Management in Node.js

How AsyncLocalStorage solves context management in asynchronous Node.js apps

AsyncLocalStorage gives you a way to maintain context across your async operations without manually passing data through every function. Think of it like having a secret storage box that follows your request around, carrying important information that any part of your code can access.

Here’s what a typical Express application without AsyncLocalStorage might look like. We need to pass the userId through multiple functions:

Notice how we keep passing userId everywhere? Now multiply this by several more parameters like requestId, tenantId, and locale. The function signatures grow unwieldy fast.

Here’s how we can clean this up with AsyncLocalStorage

The context follows the request through its entire lifecycle. No more parameter passing.

When to Use AsyncLocalStorage

Here’s where AsyncLocalStorage shines: tracking requests as they flow through your microservices. You can log the request ID, trace ID, and other metadata without passing them through every function.

AsyncLocalStorage keeps track of the current transaction across your database operations. This is useful when you need to pass the transaction object through multiple functions:

AsyncLocalStorage is also useful for logging. You can store the current log context and retrieve it in any function.

When you run this, each log message automatically includes the full request context:


When Not to Use AsyncLocalStorage

While AsyncLocalStorage is powerful, I avoid it when:

  • The context only needs to flow through a couple of functions - regular parameter passing is clearer.
  • Working with synchronous code - AsyncLocalStorage adds unnecessary complexity.
  • When you build a public API using AsyncLocalStorage, you’re forcing a specific way of managing context onto your users. Consider a payment processing API:

Your API consumers now must wrap every call in storage.run(), which might not fit their application’s architecture.

They can’t simply call processPayment() directly with a user ID. Instead of writing straightforward code like await processor.processPayment(100, userId), they’re forced into this more complex pattern:

A more flexible approach would make the context optional while still supporting AsyncLocalStorage

This approach gives API consumers the freedom to choose their preferred approach while maintaining compatibility with AsyncLocalStorage when needed. They can either use the context storage or pass parameters directly, fitting their specific use case and architecture.

AsyncLocalStorage might seem like magic at first, but understanding its boundaries helps you use it effectively. When used appropriately, it significantly cleans up your code and makes context management a breeze.

If you found this article helpful, you might enjoy my free newsletter. I share developer tips and insights to help you grow your skills and career.



This article was originally published on https://www.trevorlasn.com/blog/node-async-local-storage. It was written by a human and polished using grammar tools for clarity.