What is row-level security (RLS)?

When app code forgets a filter, the database still holds back the rows your user shouldn't see.

An admin approves every new account by hand. Nothing is created until then. We reply by email; no newsletter, no sequence.

Want to see it first? Book a demo

app.salescrew.io/inbox
The unified reply inbox with classified threads

RLS — Row-level security (RLS) is a database feature that attaches access policies to individual rows. A query returns only the rows the current user is allowed to see, enforced by the database rather than the application. It protects data even when application code is wrong.

Also known as: row-level security

Why it matters

Most apps rely on their own code to decide what a user may see. That code filters results before they reach your screen. Row-level security moves that choice down into the database itself. You attach a policy to a table that says which rows a given user may read or write. Your database then applies it on every query, whatever the app's code asked for. If a bug in the app forgets to filter a query, RLS still blocks rows the user shouldn't see. The block holds even when the app gets it wrong.

What trips teams up is how several policies on the same table combine. In most setups, policies join with OR logic by default. A row shows up if it meets any one policy that applies, not only if it meets all of them. That's the trap. One loose policy, maybe written for an in-house tool or to make testing easier, can quietly undo every strict policy on the same table. It opens up rows those other policies were meant to guard. So you should check how the policies on a table work together, not only whether each looks right on its own. That's what catches the problem before real data leaks.

How RLS is applied

  1. 1

    Enable RLS on a table

    The table goes from open access to access gated by policy.

  2. 2

    Define access policies

    You write rules that say which rows a given user or role may see or change.

  3. 3

    A query runs against the table

    Any query, from the app or a direct link, has to pass the policies.

  4. 4

    The database filters rows

    Only rows that match a policy are returned or changed.

  5. 5

    Policies are reviewed for how they combine

    The policies on one table are checked together, not only one by one.

The mistake to watch for

Combining RLS policies without checking how they combine. Policies are OR-ed by default. One permissive policy defeats every restrictive one.

Questions

How is RLS different from role-based access control?
Role-based access control most often sets what a role can do in the app or in a feature. RLS sets which rows in a database table a query returns. The database applies it, whatever the app meant to do.
Does RLS protect against bugs in application code?
Yes, and that's one of its main strengths. The database applies the policy rather than trusting the app to filter right. A bug in app code that forgets a filter still can't expose rows the RLS policy blocks.
Why is it dangerous to add a permissive RLS policy?
Policies on the same table are most often joined with OR logic. One policy that grants broad access, even one added for a small in-house job, can override every stricter policy on that table.