{"id":12998,"library":"continuation-local-storage","title":"Continuation-Local Storage (Userland)","description":"This package provides a userland implementation of Continuation-Local Storage (CLS) for Node.js, a mechanism akin to thread-local storage but adapted for Node's asynchronous callback chains. It allows developers to store and retrieve values that are scoped to the lifetime of a sequence of asynchronous function calls, eliminating the need to explicitly pass context objects (like request IDs or user information) through numerous function parameters. Values are managed within named 'namespaces' using `createNamespace()`, `getNamespace()`, and propagating context via `namespace.run()` or `namespace.bind()`. While a valuable concept, this specific `continuation-local-storage` package (version 3.2.1, last published 8 years ago) is considered superseded. Modern Node.js applications should leverage the native `AsyncLocalStorage` API (available since Node.js v13.10.0, backported to v12) for a more robust and performant solution, or `cls-hooked` for older Node.js versions, both of which utilize `async_hooks`.","status":"abandoned","version":"3.2.1","language":"javascript","source_language":"en","source_url":"https://github.com/othiym23/node-continuation-local-storage","tags":["javascript","threading","shared","context","domains","tracing","logging"],"install":[{"cmd":"npm install continuation-local-storage","lang":"bash","label":"npm"},{"cmd":"yarn add continuation-local-storage","lang":"bash","label":"yarn"},{"cmd":"pnpm add continuation-local-storage","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"This package is CommonJS-first; use `require` syntax. ESM imports would require transpilation.","wrong":"import { createNamespace } from 'continuation-local-storage';","symbol":"createNamespace","correct":"const createNamespace = require('continuation-local-storage').createNamespace;"},{"note":"Access named exports directly from the `require` call. Attempting ESM imports without a CJS wrapper will fail.","wrong":"import { getNamespace } from 'continuation-local-storage';","symbol":"getNamespace","correct":"const getNamespace = require('continuation-local-storage').getNamespace;"},{"note":"The `Namespace` is an interface/concept, not a directly exposed class for instantiation via `require`. You interact with instances returned by `createNamespace`.","wrong":"const { Namespace } = require('continuation-local-storage'); // Namespace is an interface/type, not a directly exported class","symbol":"Namespace","correct":"const cls = require('continuation-local-storage');\nconst session = cls.createNamespace('my session');"}],"quickstart":{"code":"const createNamespace = require('continuation-local-storage').createNamespace;\n\nconst requestContext = createNamespace('requestContext');\n\nfunction handleRequest(requestId) {\n  requestContext.run(function () {\n    requestContext.set('requestId', requestId);\n    console.log(`[${requestContext.get('requestId')}] Request started.`);\n\n    // Simulate an asynchronous database call\n    setTimeout(() => {\n      logActivity('Fetching user data...');\n\n      // Simulate another async operation within a nested context\n      requestContext.run(function (nestedContext) {\n        // nestedContext is a copy of the parent context\n        logActivity('Processing user data in nested context...');\n        requestContext.set('operation', 'processUser');\n        // The original requestId is still available\n        console.log(`[${requestContext.get('requestId')}:${requestContext.get('operation')}] Nested operation active.`);\n\n        setTimeout(() => {\n          logActivity('Nested operation complete.');\n        }, 50);\n      });\n\n    }, 100);\n  });\n\n  function logActivity(message) {\n    const currentRequestId = requestContext.get('requestId') || 'N/A';\n    const currentOperation = requestContext.get('operation') || 'N/A';\n    console.log(`[${currentRequestId}:${currentOperation}] ${message}`);\n  }\n}\n\n// Simulate multiple incoming requests\nhandleRequest('req-1');\nsetTimeout(() => handleRequest('req-2'), 20);\nsetTimeout(() => handleRequest('req-3'), 150); // This will run after req-1's initial context might have exited\n\n// Demonstrates that context is isolated and automatically managed across async calls.\n// The logActivity function correctly picks up the context for the active request chain.","lang":"javascript","description":"This quickstart demonstrates how to establish and retrieve context within asynchronous call chains using namespaces, including nested contexts, for simulated HTTP requests."},"warnings":[{"fix":"For Node.js v12.17.0+ or v13.10.0+, use `AsyncLocalStorage` from `node:async_hooks`. For older Node.js versions, consider `cls-hooked` which is an `async_hooks` based polyfill. Example: `const { AsyncLocalStorage } = require('node:async_hooks'); const als = new AsyncLocalStorage(); als.run(() => als.getStore().set('key', 'value'));`","message":"This userland implementation of Continuation-Local Storage is largely superseded by Node.js's native `AsyncLocalStorage` API (introduced in v13.10.0, backported to v12). `AsyncLocalStorage` offers superior performance, stability, and integration with the Node.js event loop and `async_hooks`. It is strongly recommended to migrate to the native API for new projects and consider it for existing ones.","severity":"breaking","affected_versions":">=3.0.0 (all versions)"},{"fix":"Ensure all asynchronous callback functions (especially those passed to external libraries or promise chains) are explicitly bound to the current namespace using `namespace.bind(fn)` or `namespace.run(fn)` where applicable. If context loss persists, inspect the specific library's async behavior or consider migrating to `AsyncLocalStorage` which has better compatibility due to being a native primitive.","message":"Context can be lost when integrating with certain third-party libraries, especially those that extensively use promises, custom async patterns, or do not properly 'bind' functions to the CLS context. This can lead to subtle and difficult-to-debug issues where context values unexpectedly become `undefined`.","severity":"gotcha","affected_versions":">=3.0.0"},{"fix":"Regularly test application behavior across Node.js versions and dependency updates. The most robust solution is to migrate to the native `AsyncLocalStorage` API which avoids userland monkey-patching concerns entirely.","message":"This module's approach, like other userland CLS implementations, may involve monkey-patching Node.js internals, which can lead to fragility. Updates to Node.js or other dependencies might inadvertently break the context propagation or introduce unexpected behavior, making maintenance challenging.","severity":"gotcha","affected_versions":">=3.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure that all code paths where `namespace.get()` is called are encapsulated within a `namespace.run()` block, or that relevant functions are explicitly `namespace.bind()`-ed. If using promises, special care must be taken to bind promise callbacks or use a promise-aware CLS library (like `cls-hooked`) or `AsyncLocalStorage`.","cause":"Attempting to retrieve a value from a Continuation-Local Storage namespace (`namespace.get()`) when no active context has been established by `namespace.run()` or `namespace.bind()` for the current asynchronous chain. This often happens if an async operation 'escapes' the CLS context.","error":"TypeError: Cannot read property 'get' of undefined"},{"fix":"This package is not fully compatible with modern `async/await` syntax. Migrate to `cls-hooked` for older Node.js versions or, ideally, `AsyncLocalStorage` for Node.js v12.17.0+ / v13.10.0+. These alternatives are designed to work correctly with promises and `async/await`.","cause":"The `continuation-local-storage` package has known limitations and often fails to correctly propagate context across modern `async/await` patterns or with certain promise implementations.","error":"Continuation-local storage context is lost after async/await call"},{"fix":"This is often a transient warning related to older dependency trees. If possible, upgrade all related packages to their latest versions. If the warning persists and is caused by this package directly, the best long-term solution is to migrate away from `continuation-local-storage` to `AsyncLocalStorage` or `cls-hooked`.","cause":"This specific warning was observed with older versions of `request-promise` or similar libraries that had `continuation-local-storage` as a peer dependency, but might not be fully compatible or would cause issues upon installation.","error":"WARNING: continuation-local-storage is still present as a peer dependency on npm and causes warnings."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":""}