Yieldless
Reference

yieldless/context

AsyncLocalStorage-based context and a small tracing helper for Node.js.

yieldless/context wraps Node's AsyncLocalStorage without turning it into a global application container.

Exports

  • createContext<T>(): YieldlessContext<T>
  • createTraceContext<Span>(): YieldlessContext<Span>
  • withSpan(tracer, context, name, fn): Promise<Return>

YieldlessContext<T>

MethodDescription
run(value, fn)Execute a function with the given context value
get()Return the current value or undefined
expect(message?)Return the current value or throw with an optional message
bind(fn)Capture the current context and bind it to a function

Example

import { createContext, withSpan } from "yieldless/context";

const requestContext = createContext<{ requestId: string }>();

await requestContext.run({ requestId: crypto.randomUUID() }, async () => {
  console.log(requestContext.expect().requestId);
});

Tracing shape

withSpan() expects a tracer with startActiveSpan() and a span with end(). That matches the OpenTelemetry style API closely without taking a hard runtime dependency on it.

Use it for

  • Request IDs
  • Trace spans
  • User session metadata
  • Transaction handles

Do not use it for

  • Static application dependencies
  • Feature flags that are known at startup
  • Anything that would be clearer as a regular function argument

Good

Use context for metadata that naturally follows asynchronous work.

const requestContext = createContext<{ requestId: string }>();

await requestContext.run({ requestId }, async () => {
  logger.info(requestContext.expect().requestId);
  await handleRequest();
});

Use bind() when a callback will run later but should keep the current store.

const onComplete = requestContext.bind(() => {
  logger.info(requestContext.expect().requestId);
});

Avoid

Do not use async context as a dependency container.

const appContext = createContext<{ database: Database; logger: Logger }>();

export async function loadUser(id: string) {
  return await appContext.expect().database.findUser(id);
}

Stable dependencies are clearer as function parameters or yieldless/di inputs.

On this page