AsyncLocalStorage for Easy Context Passing in Node.js

Roman Coedo
Trabe
Published in
2 min readMay 25, 2020
Photo by Steve Johnson on Unsplash

Some months ago I wrote a post about storing data in an asynchronous context using continuation local storage to avoid spreading the request context to every function via parameters. For this purpose, we used cls-hooked, a library that implements CLS using the async_hooks node API.

With Node.js 13.10, we got a new feature called AsyncLocalStorage. In this post we’re going to learn more about this new feature and we’re going to rebuild our previous solution using AsyncLocalStorage this time.

So, what is AsyncLocalStorage?

AsyncLocalStorage is a new experimental feature included in the async_hooks package that allows us to store data in asynchronous contexts just like we were doing with cls-hooked. You can think of it as the node.js alternative to thread local storage.

AsyncLocalStorage’s API is really close to the cls-hooked API so the examples from our previous post should translate pretty easily.

Let’s get into it!

Building an Express middleware

In our previous post we started by creating a namespace. Namespaces are used to scope global data.

With the new Node.js API we create AsyncLocalStorage instances instead:

Our middleware using cls-hooked looked like this:

Which translates, using the new Node.js API, to something like this:

The asyncLocalStorage.run method takes two arguments. The first one is our store state, which can be anything we want. In our example we are using a map to have a key/value storage for the request. The second argument is a function. Our state will be retrievable and isolated inside that function, so we call next() inside that function to have every other express middleware run within the AsyncLocalStorage context.

Our complete express example would look like this:

Revisiting CLS performance

In our previous post we talked about how the async_hooks API adds a significant overhead to our application. However, the new AsyncLocalStorage performs better than the library we were using before.

For context, here’s a link to a benchmark made by Andrey Pechkurov.

Enjoy!

--

--