What Is Row-Level Security (and Why Your App Needs It)

Row-level security controls which rows each user can see or change, so people sharing a database don't see each other's data. This guide covers when you need it and how to set it up.

Bubble
September 01, 2026 • 6 minute read
What Is Row-Level Security (and Why Your App Needs It)

TL;DR: Row-level security (RLS) is a database feature that automatically filters which rows each user can see or modify, based on who they are: their identity, role, or group. Any app where different users share a database but shouldn’t see all the data needs RLS security.

Imagine your app’s database as a filing cabinet the whole office shares. Without any locks, anyone can read everything inside. You can lock an entire drawer, but then either everyone in the office can open it, or no one can. What do you do if people need to share a file drawer without seeing each other’s folders?

That’s the problem row-level security solves. It’s how sales reps see only their own deals and patients see only their own records, even though they all share the same table in a database.

This guide covers what row-level security is, how it compares to field-level and table-level controls, when to use it, common mistakes to avoid, and how Bubble handles it visually, with no SQL required.

What is row-level security?

Row-level security (RLS) is a database feature that automatically controls which rows a user can see or change, based on attributes like their user ID, role, or group.

Think of it as an invisible filter the database applies to every query. When a sales rep looks up the “Orders” table, the database limits results to rows where the owner matches their own user ID, so the rep gets back only their own orders, without ever knowing the filter exists.

Keeping that filter working is important. Broken access control (letting people see or change data they shouldn’t be able to) is the top security risk facing web applications. It usually happens when an app is responsible for enforcing a rule and simply forgets to, so it’s better to enforce the filter directly from the database.

Row-level security lives right inside the database. That means the same rule, called a predicate, applies no matter how someone connects to that database: through your app, a reporting tool, an API, or a direct query.

🔍
Row-level security (RLS) is a database feature that automatically filters which rows a user can see or modify, based on their user ID, role, or group.

How does row-level security work?

Every time someone runs a query against an RLS database, the database checks the policy first. It looks at who’s asking (their user ID, role, or department) and filters the rows to match, before anything comes back. You never see rows you’re not allowed to, and you won’t get an error hinting they exist either.

Three things make this work:

  • It’s automatic. The database applies the policy on every query, without anyone asking it to. A support agent looking up the “Tickets” table doesn’t have to filter to their own queue themselves. The database already limits results to tickets assigned to them.
  • It knows who’s asking. The database reads session variables (a user ID, role, or department) the moment someone logs in. A support agent and their supervisor can run the exact same query against “Tickets” and see different results: The agent gets only their assigned tickets, while the supervisor sees the whole team’s queue.
  • It works everywhere. The RLS policy applies no matter how someone connects to the database, not just through your app. That means a misconfigured frontend or a missed permission check in your code can’t accidentally expose rows it shouldn’t. The exception is privileged accounts, which can sometimes bypass policies depending on the system.

Take a multi-tenant SaaS app, where customers share the same “Projects” table. Each project has a tenant_id field marking which customer it belongs to. The RLS policy checks your tenant_id and only returns matching projects. Customer A never sees Customer B’s projects. That happens automatically, before any of your app’s own logic even runs.

Row-level security vs. field-level and table permissions

These three controls sound similar, but they’re not doing the same job. Row-level security decides which rows you get to see. Field-level security zooms in further, hiding specific fields within those rows. Table-level permissions lock down an entire table at once. Most apps end up using all three together.

Think back to the filing cabinet. Table permissions lock the whole drawer shut. Row-level security decides which folders you’re allowed to pull out, while field-level security blacks out specific lines once you’ve got the folder open.

Control What it restricts Example
Table/object permissions Access to an entire table or view Block non-admin users from the "Payroll" table entirely
Row-level security Which records within a table a user can see or modify A sales rep sees only their own deals in the "Deals" table
Field-level security Which fields within a row are visible Hide the "Salary" field from all users except HR

To set up these in order, start with table access first, then row policies to filter which records show up, and then field restrictions on anything sensitive.

Here’s what that looks like in a healthcare app: A clinician might get table-level permission to open a “Patients” table. But when she opens it, row-level security narrows what she sees down to just her own patients. Field-level security hides billing and insurance fields entirely, because she doesn’t need to see them.

🛡️
Row-level security controls which rows a user can see. Field-level security controls which fields within those rows they can see. They answer different questions, and most apps that need one need both.

When should you use row-level security?

If different users of your app need to see different slices of the same data, you probably need row-level security. The clearest sign is when you keep adding the same “only show this user’s own records” condition, over and over, in different parts of your app. That’s usually a signal the database should be enforcing that boundary for you, automatically.

Here are a few places RLS solves access problems:

  • Multi-tenant SaaS apps: When multiple customers share the same database tables, row-level security keeps each tenant’s data invisible to everyone else. Say a project management tool stores Company A’s and Company B’s projects in the same “Projects” table. RLS guarantees Company A never sees Company B’s records, even if there’s a bug in the app that fails to filter correctly.
  • Role-based employee access: Row-level security lets you scope data by department, seniority, or region, without duplicating the table. A regional sales manager sees only deals in their territory, while a national director sees deals across every region.
  • Healthcare and regulated industries: In regulated spaces like apps that follow HIPAA, minimum-necessary access rules mean you’re expected to limit patient data access by role. Row-level security is a safer way to stay compliant than a manual check buried somewhere in your app’s code.
  • Compliance and audit requirements: Centralizing your data-access policies also makes security audits easier. Your team has one place to check the rules instead of hunting through dozens of files, and you can point auditors to the database policies that govern every query.
💡
Any app where different users share a database but shouldn’t see all the data needs row-level security.

What are the risks of row-level security?

Row-level security stops most accidental data exposure, but the stakes are still high enough that a bad setup matters. The global average cost of a data breach was $4.44 million in 2025, and it doesn’t take much of a misconfiguration to open a real gap. Here’s what to watch for:

  • Admin and owner bypass: Some database engines let table owners and admins skip RLS policies entirely by default. Close that gap by turning on a “force” option in the engine, if it has one, or by writing your policies to explicitly cover admin accounts too. Test with both standard and privileged accounts, so you know the boundary holds.
  • Missing write checks: Read and write access are often governed by separate policies. If you set up a read policy but skip the write policy, users might be blocked from viewing certain records while still able to edit them through a direct API call or a form. Set up both together, every time.
  • Performance impact: The database checks a predicate on every single query, so a complex or unindexed policy condition can slow things down. If your policy filters on a tenant_id or owner_id column, index it to keep queries fast.
  • Debugging opacity: When row-level security filters out a row, the user just sees nothing. There’s no error message and no hint that a hidden
Start building for free

Build for as long as you want on the Free plan. Only upgrade when you're ready to launch.

Join Bubble

LATEST STORIES

blog-thumbnail

What Can You Build on Bubble? 25 Examples to Inspire You

From personal finance apps to SaaS tools, custom marketplaces to AI apps, see how others are using Bubble to build… well, just about everything.

Bubble
September 08, 2026 • 13 minute read
blog-thumbnail

The Business of Building 2026: What Separates Apps That Make Money

Everyone talks about how fast you can build an app now. We studied 250,000 Bubble apps to find what separates the ones that turn into real businesses.

Bubble
September 08, 2026 • 4 minute read
blog-thumbnail

The 7 Best AI-Powered App Builders for Operations Teams in 2026

Discover the best AI app builders for operations teams — comparing platforms across governance capabilities, mobile deployment options, workflow transparency, and pricing models to help you choose the right tool for internal apps, partner portals, and field applications.

Bubble
September 07, 2026 • 18 minute read
blog-thumbnail

Destination Bubble: How We Turned Our 14th Birthday Into a Company-Wide Adventure

Here's how the People team turned Bubble's birthday into a weeklong celebration and moment for connection.

Frannie Melegrito
September 04, 2026 • 3 minute read

How to Set Up an Apple Developer Account: Step-by-Step

September 04, 2026 • 10 minute read

How to Add Stripe Integration to Your No-Code App

September 04, 2026 • 10 minute read

A Guide on How to Build a Healthcare App Without Code

September 03, 2026 • 9 minute read

How to Set Up In-App Purchases on Bubble

September 03, 2026 • 9 minute read

How to Turn a Spreadsheet Into an App: A 2026 Guide

September 03, 2026 • 12 minute read

Build the next big thing with Bubble

Start building for free