Row-level security works by injecting a WHERE clause into the database query at the moment a user runs a report — automatically, based on who that user is. The user never sees this filter; they can't remove it or work around it. They simply get back the subset of rows they're permitted to see. The mechanism is straightforward in concept, but the implementation approach varies significantly across platforms — and those differences have real consequences for maintainability, performance, and administrative overhead.
This chapter explains the main implementation approaches, their tradeoffs, and what questions to ask when evaluating a BI tool's RLS capabilities.
Static vs. Dynamic Row-Level Security
The most fundamental distinction in RLS implementation is whether the filter values are hardcoded into the policy (static) or resolved at runtime based on the user's identity (dynamic).
Static RLS
Static RLS means the filter rule contains a literal value. A policy that says "show only rows where region = 'Southeast'" is static — it always applies the same filter regardless of who's running the report. You'd create one policy for Southeast, another for Northwest, another for Central, and assign each to the appropriate users or groups.
Static RLS is straightforward to set up and easy to understand. For simple, stable use cases — a report that three specific people should see filtered to their fixed set of values — it works fine. The problem is management overhead at scale. Every time someone changes regions, or you add a new region, or you onboard a new client, you're creating or editing policies manually. At 10 users it's manageable. At 100 users across 30 clients, it becomes a full-time administrative task.
Dynamic RLS
Dynamic RLS resolves the filter value at query time based on a user attribute. Instead of hardcoding "region = 'Southeast'", the policy says "region = [current user's region attribute]". When the user runs the report, the system looks up their region, inserts that value into the WHERE clause, and returns the appropriate rows.
This is the approach that scales. You configure the policy once. As you add users, you assign them the appropriate attribute value (a region, a tenant ID, a client name) — and the policy automatically handles the filtering. Adding a new client doesn't require a new policy; it requires assigning the new client's identifier to their user accounts.
Static RLS: you create one policy per user group, hardcoding the filter values. 50 clients = 50 policies to maintain. Dynamic RLS: you create one policy that references a user attribute. 50 clients = one policy, with the attribute value assigned per user or group. Dynamic is almost always the right approach once you have more than a handful of distinct data segments to manage.
Where the Filter Is Applied: Query-Time vs. Report-Time
A second important dimension is when in the data pipeline the filter is applied.
Filter at Query Time (Database Layer)
The cleanest implementation applies the security filter at the database query level — before data ever leaves the database. The BI tool constructs the SQL query with the user's security constraints already embedded as WHERE clause conditions. The database engine applies the filter; only permitted rows are returned to the application layer.
This approach is the most secure because the data restriction happens at the source. There's no pathway by which a user could access the unfiltered data through an API call, a caching layer, or a platform vulnerability — the database simply never returns rows the user isn't permitted to see. It's also generally more performant, since the database engine can use indexes on the filtered columns.
Filter at Report/Application Layer
Some implementations pull a broader dataset and then filter it at the application or report layer before displaying it to the user. This is simpler to implement but creates risk: the full dataset exists in memory or in a cache somewhere between the database and the screen. Depending on the implementation, a sophisticated user or a platform vulnerability could potentially access that broader dataset.
For most business applications this risk is theoretical rather than practical, but for compliance-sensitive environments — healthcare, finance, legal — query-time filtering is worth specifically asking about.
How User Attributes Map to Data Filters
Dynamic RLS requires a way to store per-user or per-group attribute values that the security policy can reference. Different platforms handle this differently.
User Profile Attributes
The simplest approach stores a security attribute directly on the user's profile. A field called region on the user record holds "Southeast" for one user and "Northwest" for another. The RLS policy references this profile field. The main limitation is that profile attributes are typically one-to-one: a user has one region, one department, one client assignment. If a user needs access to multiple segments — a manager overseeing three regions — this approach gets awkward.
Group-Based Attributes
A more flexible approach stores security attributes at the group level and assigns users to groups. All users in the "Southeast Region" group see Southeast data. This makes user management cleaner: changing a user's data access means moving them between groups, not editing individual profile attributes. It handles the "one user, multiple segments" case better — a manager can belong to multiple groups.
Data Tags (Tag-Based Attributes)
Some platforms implement a dedicated tagging system specifically designed for security filtering — a more structured version of group-based attributes that's purpose-built for RLS. The administrator defines named tags (e.g., "tenant_id", "region", "client_name"), assigns values to users or groups, and the security policy references the tag name as a dynamic parameter. This is the approach DashboardFox uses, and it's covered in detail in Chapter 4.
Performance Considerations
RLS adds a WHERE clause to every query. For most datasets this overhead is negligible — database engines are designed to filter efficiently, especially when the filter column is indexed. The scenarios where RLS performance becomes a concern are:
High cardinality filter columns without indexes. If you're filtering on a column with millions of distinct values and no index, every query becomes a full table scan. The fix is indexing the columns used as RLS filter targets — something your database administrator can handle.
Complex multi-condition policies. If a user's data access is determined by multiple attributes combined with AND/OR logic, the resulting WHERE clause can get complex. This is solvable with proper query design and indexing, but it's worth understanding before you build policies that reference six different attributes.
Caching interactions. If your BI tool uses query result caching, RLS and caching need to interact correctly — the cached result for User A cannot be served to User B. Most mature BI platforms handle this correctly (they cache per user or disable caching for RLS-protected queries), but it's worth verifying, especially for tools where caching is a recent addition.
DashboardFox applies security filters at query time — so restricted data never leaves the database. See how it's implemented on the security overview, or try it hands-on in a free trial.
The Four-Layer Security Stack
RLS is one layer in a complete BI security architecture. Understanding where it fits helps clarify what it does and doesn't control:
Layer 1 — Authentication: Who can log in at all. Username/password, SSO, session tokens. Controls the front door.
Layer 2 — Access control: Which reports, dashboards, and folders a logged-in user can see in the library. A user might be able to log in but only see dashboards relevant to their role.
Layer 3 — Role-based permissions: What a user can do with the reports they can see — view only, edit, export, share, delete. Prevents users from modifying reports they're allowed to view.
Layer 4 — Data-level security (RLS): Which rows of data are returned when the user actually runs a report they have access to. This is the layer that enforces data isolation between users sharing the same reports.
All four layers work together. A sales rep might be authenticated (Layer 1), able to see the Sales Performance dashboard (Layer 2), view-only on that dashboard (Layer 3), and filtered to see only their own accounts (Layer 4). Each layer addresses a different security question. RLS only answers the last one: given that this user can run this report, what data should they see?
What to Ask When Evaluating RLS in a BI Tool
When you're evaluating a BI platform's RLS capabilities, these are the questions that matter:
Is filtering applied at query time (database layer) or at the application layer? Does the platform support dynamic filtering based on user attributes, or only static hardcoded values? Can one user be assigned to multiple security groups with different filter values? Does RLS interact correctly with caching — are results isolated per user? Is RLS available at every pricing tier, or gated behind an enterprise upgrade?
That last question is more significant than it sounds. As the next chapter covers, the cost of accessing RLS varies dramatically across platforms — from included in every plan to gated behind tiers that cost $500+ per month more than the entry tier.
