Postgres RLS performance: Indexing, not policy evaluation, drives speed
Ashwin Sridhar's experiment on dev.to benchmarks Postgres Row-Level Security, revealing minimal overhead from policy evaluation and significant performance gains from proper indexing for multi-tenant…
Ashwin Sridhar's experiment on dev.to benchmarks Postgres Row-Level Security, revealing minimal overhead from policy evaluation and significant performance gains from proper indexing for multi-tenant applications.
TL;DR
Best for: Multi-tenant applications requiring strong data isolation at the database level, particularly those with a tenant_id column.
Skip if: Your application architecture does not require database-level tenant isolation, or if you cannot guarantee proper indexing on tenant identifiers.
Bottom line: Postgres Row-Level Security (RLS) policies introduce negligible performance overhead; the critical factor for scalable performance is the presence of an appropriate index on the tenant_id column.
METHODOLOGY
This v0 review draws on Ashwin Sridhar's published claims and experimental data on dev.to, accessed on May 29, 2026. The review covers the performance characteristics of Postgres Row-Level Security (RLS) as measured by Sridhar, focusing on the impact of RLS policy evaluation versus indexing on query latency. The experiment used a single table with 1 million rows, where one tenant owned approximately 100,000 rows. Performance was measured across 50 timed executions per condition, discarding the first three as warmups, and reporting p50, p95, and p99 latency. Four conditions were tested: superuser without index (A), app_role without index (B), superuser with index (C), and app_role with index (D). Three query types were used: a simple LIMIT 100 fetch, a filtered scan with a second condition, and a full COUNT(*) query. This review does not include independent performance benchmarks, long-term workflow analysis, or edge-case testing. Update cadence: re-tested when claims diverge from observed behavior.
WHAT IT DOES
Enforces tenant isolation at the database level
Postgres Row-Level Security (RLS) allows database administrators to define policies that restrict which rows a user can see or modify in a table. When an application user (operating under a specific app_role) queries a table with an RLS policy, Postgres implicitly appends an invisible WHERE clause to their query. This ensures that the user only interacts with rows belonging to their assigned tenant, without requiring explicit filtering in the application code or ORM layer. Superusers bypass these policies entirely.
Measures RLS overhead
Ashwin Sridhar's experiment directly measures the performance cost of RLS policy evaluation. By comparing queries run as a superuser (bypassing RLS) against queries run as an app_role (activating RLS) on identical hardware and data, without an index, the study isolates the overhead introduced by RLS itself. The findings indicate this overhead is minimal, even on heavy COUNT(*) queries scanning 1 million rows.
Quantifies index impact
The experiment also quantifies the performance benefit of indexing the tenant_id column. By introducing an index and re-running the same queries under both superuser and app_role conditions, Sridhar demonstrates how proper indexing dramatically reduces query latency. This highlights the interaction between RLS and database optimization techniques.
WHAT'S INTERESTING / WHAT'S NOT
What's interesting about Ashwin Sridhar's work is its direct, data-backed debunking of a common architectural concern. The idea that Postgres RLS inherently ruins performance is a persistent myth, often leading developers to implement complex, error-prone application-level filtering. Sridhar's experiment provides concrete numbers: RLS policy evaluation, on its own, adds less than 2% latency, or approximately 1.6ms on a full table scan of 1 million rows. This overhead is, as he puts it,
Every claim ties to a primary source. See our methodology.