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
Externalized authorization is becoming a data-layer governance pattern, not just an app design choice. The article shows a shift from scattered in-code checks to centrally evaluated policy that can be translated into query execution. That reduces policy drift, but it also changes where identity control is actually enforced. For IAM and application security teams, the decision is no longer whether to authorize, but where to place the decision so it can scale with the workload and the database.
A few things that frame the scale:
- 97% of NHIs carry excessive privileges, increasing unauthorised access and broadening the attack surface, according to Ultimate Guide to NHIs.
- Only 5.7% of organisations have full visibility into their service accounts, which means query-layer controls still depend on incomplete identity inventory in many environments.
A question worth separating out:
Q: How do teams know whether externalized authorization is working correctly?
A: Look for three signals: denied requests return empty sets without extra reads, conditional plans translate into database-native filters, and relation-based rules resolve correctly across joins. If the application still fetches broad datasets and filters afterward, the control is not operating at the query layer.
👉 Read our full editorial: Externalized authorization shifts policy enforcement into the query layer