node-simple-context is a minimalist, type-safe context manager for Node.js, inspired by React Context.
Built on top of AsyncLocalStorage, it provides isolated contexts that work seamlessly with async/await and promises — with zero runtime dependencies.
This library is highly inspired by nctx. You definitely should check it out! Thanks to @devthejo for his help.
npm install node-simple-contextDefine a schema for compile-time type safety on keys and values:
import { createSimpleContext } from 'node-simple-context';
type RequestSchema = {
userId: string;
role: 'admin' | 'user';
requestId: string;
};
const context = createSimpleContext<RequestSchema>();
context.set('userId', '12345'); // OK
context.set('role', 'admin'); // OK
context.set('role', 'invalid'); // Type error!
context.set('unknown', 'value'); // Type error!
const userId = context.get('userId'); // string | undefined
const role = context.get('role'); // 'admin' | 'user' | undefinedWithout a schema, all string keys are accepted and values are unknown:
const context = createSimpleContext();
context.set('foo', 'bar');
context.set('count', 42);
const value = context.get('foo'); // unknown | undefinedCreates a new SimpleContext instance. Optionally accepts a type parameter defining the context's keys and value types.
import { createSimpleContext } from 'node-simple-context';
// Untyped
const context = createSimpleContext();
// Typed
type MySchema = { userId: string; count: number };
const typedContext = createSimpleContext<MySchema>();Retrieves a value from the context by key.
Parameters:
key- The key to retrieve. Must be a non-empty string.
Returns: The value associated with the key, or undefined if not found.
Throws: TypeError if key is not a string or is empty.
Example:
const userId = context.get('userId'); // string | undefined (with typed schema)Sets a value in the context by key.
Parameters:
key- The key to set. Must be a non-empty string.value- The value to associate with the key. Must match the schema type.
Throws: TypeError if key is not a string or is empty.
Example:
context.set('userId', '12345');Deletes a value from the context by key.
Parameters:
key- The key to delete. Must be a non-empty string.
Returns: true if the key existed and was deleted, false if it didn't exist.
Throws: TypeError if key is not a string or is empty.
Example:
context.delete('userId');Checks if a key exists in the context.
Parameters:
key- The key to check. Must be a non-empty string.
Returns: true if the key exists, false otherwise.
Throws: TypeError if key is not a string or is empty.
Example:
if (context.has('userId')) {
console.log('User ID is set');
}Clears all values from the current context.
Example:
context.clear();Gets all key-value pairs from the current context as a plain object.
Returns: A shallow copy of all key-value pairs in the current context.
Example:
const allValues = context.getAll();
console.log(allValues); // { userId: '12345', sessionId: 'abc' }Gets all keys from the current context.
Returns: An array of all keys in the current context.
Example:
const keys = context.keys();
console.log(keys); // ['userId', 'sessionId']Gets the number of key-value pairs in the current context.
Returns: The number of entries in the context.
Example:
const count = context.size();
console.log(count); // 2Runs a callback within a forked context that inherits current values. Changes inside the fork don't affect the parent context. This is the recommended way to use fork.
Parameters:
callback- The callback to execute within the forked context.
Returns: The callback's return value.
Example:
context.set('userId', 'parent');
const result = context.fork(() => {
context.set('userId', 'child');
return context.get('userId'); // 'child'
});
context.get('userId'); // 'parent' — unchangedCreates a new forked context without a callback. Deprecated because it uses AsyncLocalStorage.enterWith() which permanently replaces the store for the entire current async execution context. Prefer fork(callback) instead.
type SessionSchema = {
userId: string;
sessionId: string;
};
const context = createSimpleContext<SessionSchema>();
// Set values
context.set('userId', '12345');
context.set('sessionId', 'abc-def');
// Check if a key exists
if (context.has('userId')) {
console.log('User is logged in');
}
// Get the number of entries
console.log(context.size()); // 2
// Get all keys
console.log(context.keys()); // ['userId', 'sessionId']
// Get all values
console.log(context.getAll()); // { userId: '12345', sessionId: 'abc-def' }
// Delete a specific key
context.delete('sessionId');
// Clear all values
context.clear();
console.log(context.size()); // 0Thanks to AsyncLocalStorage, you can fork your context to create isolated scopes in async operations:
const context = createSimpleContext();
context.set('requestId', 'root');
// Each fork gets its own isolated copy
const results = await Promise.all([
context.fork(() => {
context.set('requestId', 'req-1');
return new Promise((resolve) => {
setTimeout(() => resolve(context.get('requestId')), 100);
});
}),
context.fork(() => {
context.set('requestId', 'req-2');
return new Promise((resolve) => {
setTimeout(() => resolve(context.get('requestId')), 50);
});
}),
]);
console.log(results); // ['req-1', 'req-2']
console.log(context.get('requestId')); // 'root' — parent unchangedForks can be nested to any depth, each level isolated from the others:
const context = createSimpleContext();
context.set('level', 'root');
context.fork(() => {
context.set('level', 'child');
context.fork(() => {
context.set('level', 'grandchild');
console.log(context.get('level')); // 'grandchild'
});
console.log(context.get('level')); // 'child'
});
console.log(context.get('level')); // 'root'const contextA = createSimpleContext();
const contextB = createSimpleContext();
contextA.set('foo', 'from A');
contextB.set('foo', 'from B');
console.log(contextA.get('foo')); // 'from A'
console.log(contextB.get('foo')); // 'from B'This library supports both ESM and CommonJS:
// ESM
import { createSimpleContext } from 'node-simple-context';
// CommonJS
const { createSimpleContext } = require('node-simple-context');MIT