Request Context
AsyncLocalStorage, contextvars, context.Context — sharing state down the call tree.
The Problem Request Context Solves
As a request flows through middleware → handlers → services → database layers, each layer needs information about the request: who's the user, what's the request ID, what's the tenant ID.
Without context, you'd have to pass this as function arguments all the way down:
getUser(userId, requestId, tenantId, currentUser)
That's ugly and tightly coupled. Request context solves this: a request-scoped storage object that any function can read from during the life of one request.
How It Works
Middleware creates a context object at the start of each request. All layers can access it via an AsyncLocalStorage (Node.js), context.Context (Go), or threading.local (Python).
Node.js with AsyncLocalStorage:
const store = new AsyncLocalStorage();
// In middleware:
store.run({ requestId: uuid(), user: null }, () => {
next(); // all downstream code shares this store
});
// In a service function (no function arguments needed!):
function getCurrentUser() {
return store.getStore().user;
}
Go passes context.Context explicitly as the first argument to every function — a language idiom. Python uses contextvars.
What Goes in Context
Standard context values:
- requestId — unique UUID per request (for log correlation)
- user — authenticated user object (id, role, email)
- tenantId — for multi-tenant apps
- traceId / spanId — distributed tracing identifiers
- startTime — for computing request duration in logs
- locale — user's language preference
- permissions — pre-fetched permission set
Rules:
• Context is read-only after creation (treat it as immutable)
• Don't store mutable shared state in context
• Don't pass context values in response bodies
• Keep context small — large objects per request = memory pressure
The Backend from First Principles series is based on what I learnt from Sriniously's YouTube playlist — a thoughtful, framework-agnostic walk through backend engineering. If this material helped you, please go check the original out: youtube.com/@Sriniously. The notes here are my own restatement for revisiting later.