TL;DR: Policy evaluation can be turned into native SQL filters with a query plan adapter for Drizzle ORM, using partial evaluation to return always-allowed, always-denied, or conditional plans that the database can execute directly, according to Cerbos. That matters because authorization logic stays centralized while query-time enforcement reduces unnecessary reads, memory use, and application-layer access checks.
NHIMG editorial — based on content published by Cerbos: Externalized authorization and query plans for Drizzle ORM
Questions worth separating out
Q: How should teams implement externalized authorization without adding query overhead?
A: Use a policy engine to generate a conditional query plan, then let the database execute the filter natively.
Q: Why is query-layer authorization better suited to service identities than app-layer checks?
A: Service identities often need to evaluate large result sets, and app-layer checks force unnecessary reads before the system knows what is allowed.
Q: What do security teams get wrong about policy-to-database translation?
A: They often treat the mapper as a simple integration detail, when it is really part of the authorization control surface.
Practitioner guidance
- Centralise policy decisions before query execution Move access rules out of scattered if statements and into a single policy engine so application code only consumes decisions or query plans.
- Branch data access by plan kind Handle always-allowed, always-denied, and conditional results separately in the data layer so the application can short-circuit empty results and avoid unnecessary reads.
- Treat attribute mappings as governance assets Review every mapper from policy attributes to schema columns or relations as part of authorization design, because a stale mapping can produce correct policy logic and wrong enforcement.
What's in the full article
Cerbos' full blog post covers the operational detail this post intentionally leaves for the source:
- The exact queryPlanToDrizzle mapping pattern for turning attribute paths into Drizzle columns
- Full code examples showing how PlanKind.ALWAYS_ALLOWED, ALWAYS_DENIED, and CONDITIONAL behave in practice
- Relation mapping patterns for nested joins and many-to-many lookups
- Supported operator coverage across logical, comparison, string, existence, and collection expressions
👉 Read Cerbos' guide to query-plan authorization in Drizzle ORM →
Externalized authorization in Drizzle ORM: what changes for IAM teams?
Explore further