Skip to main content

Overview

Context in Express Zod API is the mechanism for passing data from middlewares to endpoint handlers. It enables dependency injection, authentication state sharing, and access to shared resources like database connections. Context is type-safe and accumulated through the middleware chain.

How Context Works

Context flows through your application in this order:
  1. Middlewares execute in the order they were added to the factory
  2. Each middleware returns an object that becomes part of the context
  3. Context accumulates by merging all middleware returns
  4. Endpoint handler receives the complete context object

Providing Context via Middleware

The most common way to provide context is through middleware:

Request-Independent Context

For context that doesn’t depend on the request, use addContext():
addContext() runs on every request. For expensive operations like database connections, consider using singletons or connection pools instead.

Type-Safe Context

TypeScript automatically infers the context type from your middlewares:

Context Accumulation

Context from multiple middlewares is merged:

Accessing Previous Context

Middlewares can access context from previously executed middlewares:
Context is accumulated in order. Later middlewares can access context from earlier ones, but not vice versa.

Shared Resources

Database Connections

For persistent database connections, use a singleton pattern instead of creating connections per request:
For connection pools or per-request connections:

Configuration

For static configuration, use imports instead of context:
For dynamic configuration that changes per request:

Resource Cleanup

Clean up resources in a custom Result Handler:

Common Patterns

Authentication Context

Request Metadata

Feature Flags

Tenant Isolation

Context in Result Handlers

Result handlers receive context but it may be partial if middleware execution was interrupted:
Always use the in operator to check if context properties exist in Result Handlers, since context may be incomplete if middleware execution was interrupted by an error.

Best Practices

  1. Use singletons for persistent resources: Database connections, configuration, etc.
  2. Keep context minimal: Only include what endpoints actually need
  3. Type your context: Let TypeScript infer types from middleware returns
  4. Order middlewares carefully: Authentication before authorization, etc.
  5. Clean up resources: Use Result Handlers to release connections
  6. Avoid expensive operations: Don’t create new database connections per request
  7. Check property existence: Always verify context properties exist in Result Handlers

Performance Considerations

❌ Anti-pattern: Creating connections per request

✅ Better: Use a singleton

✅ Better: Use a connection pool

See Also