Every repository method in Drizzle Castor runs through a composable middleware pipeline before any SQL reaches the database. The pipeline follows the Koa-style onion model — each middleware receives the execution context and aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/fajarnugraha37/drizzle-castor/llms.txt
Use this file to discover all available pages before exploring further.
next function, can run logic before and after the downstream chain, and must return the result of next() to pass control forward. This design lets you stack cross-cutting concerns — logging, caching, multi-tenant isolation, rate limiting, audit trails — as thin, reusable layers without touching repository code.
How the pipeline works
Drizzle Castor uses acomposeMiddleware function (see src/middleware/middleware.ts) to merge an ordered array of middleware functions into a single dispatch chain. When you call a repository method, the composed pipeline is invoked with the current ExecutionContext and the core executor as the terminal next.
ctx.state before policy enforcement occurs.
The ExecutionContext
Every middleware receivesctx, an ExecutionContext object that carries the full scope of the in-flight operation. You can read from it, write to ctx.state, and use it for correlation across nested calls.
ctx.action
ctx.action
The CRUD action being performed:
"create", "read", "update", "softDelete", "restore", or "hardDelete".ctx.tableName
ctx.tableName
The name of the target table as a string (e.g.,
"users").ctx.profile
ctx.profile
The active RBAC profile string or array of strings passed to the repository method (e.g.,
"admin" or ["user", "editor"]).ctx.params
ctx.params
A snapshot of the initial parameters:
query, data, id, filter, and set. These reflect the caller’s input before RBAC trimming.ctx.state
ctx.state
A mutable bag for sharing data between middleware layers in the same request. Initialized as an empty object; does not persist across requests.
ctx.traceId and ctx.spanId
ctx.traceId and ctx.spanId
Unique identifiers for the trace and the current execution unit.
traceId is shared across nested calls; spanId is unique per operation. Both are available in every log line automatically.ctx.metadata
ctx.metadata
User-provided contextual data attached to the trace — for example, a
userId or sessionId injected by an outer middleware.ctx.translatorContext
ctx.translatorContext
Contains the Drizzle
db instance, the registered table definitions, and the table metadata (relations, soft-delete config). Read-only for middleware.Registering middleware
Callbuilder.use(middleware, config?) on the schema builder before calling .build(). You can register multiple middleware functions; they execute in the order they are added.
Scoping middleware to specific tables or actions
Pass aMiddlewareConfig object as the second argument to restrict when your middleware fires. The tables property accepts a single table name or an array of names. The actions property accepts a single DbAction string or an array.
If you omit
tables or actions from the config, the middleware applies to all tables and all actions respectively.Practical examples
Timing middleware
Measure and log the duration of every query execution usingctx.traceId for correlation across concurrent requests.
Tenant context injection
In a multi-tenant application, inject the tenant identifier intoctx.state so downstream middleware and dynamic policies can access it without re-deriving it from the request.
Caching middleware (table-scoped)
UseMiddlewareConfig to scope a caching layer exclusively to read operations on the products table without affecting writes or other tables.
Middleware type reference
Middleware<T, TDb, TTables>
Middleware<T, TDb, TTables>
The core middleware function signature:
(ctx: ExecutionContext<TDb, TTables>, next: MiddlewareNext<T>) => Promise<T>. The generic T is the return type of the executor.MiddlewareNext<T>
MiddlewareNext<T>
A zero-argument function that returns
Promise<T>. Calling it advances the pipeline to the next middleware or the executor.MiddlewareConfig<TTables>
MiddlewareConfig<TTables>
Optional scope config:
{ tables?: TableName | TableName[]; actions?: DbAction | DbAction[] }. Omitting either field means “all”.Related pages
Telemetry & Events
Subscribe to structured events emitted by the pipeline for metrics, auditing, and observability.
Logging
Configure pattern-based, pino-powered logging with traceId correlation built in.
Access Control overview
Understand how the built-in RBAC middleware enforces action-level and field-level policies.
Schema builder methods
Full reference for builder.use(), builder.policies(), builder.withLogger(), and more.