Row Level Security
What is Row Level Security?
Row Level Security (RLS) is a powerful security layer that controls exactly which records (rows) each user can see, create, update, or delete in your application — and even which fields (columns) of those records they can see. Instead of relying on page rules and component filters alone to hide data, RLS enforces access at the data layer itself, so users only ever receive the records they are permitted to access.
RLS is the most granular and most secure level of access control in Tadabase. Once a record is excluded by RLS, it cannot be exposed by any component, page rule, custom filter, or even an API call — the user simply never sees it.
When to Use RLS
- Multi-tenant apps — each customer/company should only see their own records
- Customer portals — users should only see records that belong to them
- Sensitive data — health, financial, HR, or compliance-controlled records
- Domain APIs — when you publish data through a custom domain and want each token-authenticated caller to receive only their own records
- Field-level secrets — when most of a record is shareable but a few fields (SSN, salary, internal notes) need to be hidden or masked
How RLS Compares to Other Filtering
Tadabase already provides several ways to limit what a user sees. RLS does not replace them — it sits underneath them as the foundational ceiling of what is possible.
| Layer | Where it runs | Can a user bypass it? |
| Row Level Security | Server-side, before any other query runs | No |
| Page Rules / Layout Security | Server-side, when a page loads | No |
| Component Data Source filters (e.g. "is the Logged In User") | Server-side, scoped to one component | No, but only narrows what RLS already returned |
| Front-end Filter Tabs / Add Filters menu | Client-side, on top of returned records | Users can change them — only narrows what RLS already returned |
Think of it like this: RLS decides the universe of records a user is even allowed to know exist. Component filters and front-end filters then trim that universe down for display. They cannot widen it.
Enabling RLS on a Data Table
RLS is configured per data table. To enable it:
- Open the data table in the Data Builder.
- Click the Security tab.
- Toggle Enable row level security to ON.
- Choose a Default Behaviour (where the policies should apply).
- Optionally select Bypass Roles (users in these roles ignore RLS entirely).
- Click Save Settings, then add one or more policies.
With RLS enabled but no policies defined, the default behavior blocks all access. You must add at least one Allow policy so users can see anything in the table — or rely on Bypass Roles for trusted users.
Default Behaviour (Scope)
The Default Behaviour controls where the table's RLS policies fire:
- App Level — RLS applies only to the front-end app (the live published app users browse).
- API Level — RLS applies only to requests made through the Domain API (covered later in this article).
- Both — RLS applies to both the app and the Domain API.
Most internal tables only need App Level. Use API Level or Both when external systems or partners are pulling data through a custom domain.
Bypass Roles
Bypass Roles let specific user roles see everything in the table, ignoring all RLS policies. This is typically used for admin or super-user roles. Add roles to this list with care — anyone in a bypass role becomes effectively unrestricted on this table.
Security Policies
A security policy is a rule that says "this group of users may (or may not) perform these operations on records that match these conditions, and they may (or may not) see these fields." You can define as many policies as you need on a single table, and Tadabase combines them automatically.
Each policy is built using a five-step wizard:
Step 1 — Who the Policy Applies To
Pick which kind of user this policy targets:
| Type | Targets |
| Specific Users | Only users matching one or more user conditions (e.g. Email is the logged-in user, or Department is HR). |
| Any Logged-in Users | Every authenticated user, regardless of role. |
| Anyone (Public) | Visitors who are not logged in. Use this for publicly browsable data. |
| Specific Roles | Users assigned to one or more roles you select. |
Step 2 — Operations
Choose which actions the policy covers. You can pick any combination, or choose Full Permission to include all four:
- Read — view records
- Create — add new records
- Update — edit existing records
- Delete — remove records
Step 3 — Record Conditions
Decide which records this policy applies to:
- All records — the policy covers every row in the table.
- Only matching records — define filter conditions just like you would on a component data source. Useful operators include:
- is the logged in user — for fields connected to the Users table
- is connected to logged in user — for shared connections (e.g. user and record share the same Company)
- is connected to any of the logged in user's roles — for role-based relationships
- Standard operators: is, is not, contains, is blank, higher than, lower than, etc.
Step 4 — Effect (Allow vs Restrict)
Each policy has an effect of either Allow or Restrict:
- Allow — grants access to records that match the policy.
- Restrict — explicitly denies access to records that match, even if another Allow policy would have granted it.
When multiple policies apply to the same user, Allow policies are combined together (an OR list of permitted records), and Restrict policies are subtracted from the result. The end effect is: (any Allow matches) AND NOT (any Restrict matches).
Step 5 — Field Level Security (Optional)
RLS can also control which fields within a record this user is allowed to see. For each policy you can choose:
- Show all fields — the default, no field restrictions.
- Show only selected fields — a whitelist. Pick the fields the user is allowed to see; everything else is hidden or masked.
- Hide selected fields — a blacklist. Pick fields to remove from the response (e.g. SSN, salary).
When hiding fields you can also choose how the hidden value is presented to the user — completely removed, replaced with asterisks/dots, blanked out, or blurred. This is great for fields like Social Security Numbers, where you want users to know the field exists without revealing its value.
Policy Priority
Each policy has a numeric Priority. When multiple policies match a user, the highest-priority policies take effect. If two policies share the same priority, they combine. Use priority to handle exceptions — for example, give a baseline "Read all" policy a low priority and a stricter "Restrict pending records" policy a higher priority.
Common Policy Recipes
Here are the most common patterns. The Security tab includes Smart Templates that pre-fill these for you based on your table structure — look for them on a freshly enabled table.
| Goal | Type | Conditions | Effect / Operations |
| Users see only their own records | Any Logged-in Users | Owner field is the logged in user | Allow / Full |
| Everyone in the same company sees the same records | Any Logged-in Users | Company is connected to logged in user | Allow / Read |
| Anyone (logged-out) can read public listings | Anyone (Public) | Status is Published | Allow / Read only |
| Managers can edit, employees can only read | Specific Roles → Managers | All records | Allow / Update + Read |
| Hide salary field from non-HR roles | Any Logged-in Users (no HR role match) | All records | Allow / Read with Field Level Security hiding the Salary field |
RLS Overview & Preview
The Data Builder includes an RLS Overview screen that lists every table in your app and shows whether RLS is enabled, how many policies are defined, and what the current scope is. From the overview you can:
- Jump into any table's Security tab to edit policies
- Use View Permissions As to simulate what a specific user (or an unauthenticated visitor) would see
- Spot tables that have RLS enabled but no policies (a common cause of "I can't see any records")
Use "View Permissions As" before going live with a new policy. It runs the same evaluation as the live app and shows you exactly which records and fields the chosen user would receive — without you needing to log out and log back in as them.
RLS and the Domain API (API User Logins)
RLS is not just for the live app — it is also the foundation of Tadabase's Domain API, which lets external systems and partners log in as a real user and pull data from your app over a custom domain. Every record returned through the Domain API is filtered by the same RLS policies you configured for the app.
How It Works
- The custom domain must have Allow API Access enabled in its domain settings (see Using Custom Domains).
- On the Users data table, open the Security API tab and turn on Allow RLS Permission for API Access. This is the master switch for the Domain API.
- Configure Who can use this API? — Specific Users, Any Logged-in Users, Anyone (Public), or Specific Roles. This decides which of your app users are allowed to authenticate against the Domain API at all.
- For each table you want to expose, enable RLS and set its Default Behaviour scope to API Level or Both.
- External callers POST credentials to
https://your-custom-domain.com/loginand receive a Bearer token. Every subsequent request to/dataor/data/{table_slug}must include that token.
API Users Inherit Their RLS Permissions
This is the key point: when an external system logs in as a user via the Domain API, that token represents a real user in your Users table. Every Domain API call is then evaluated against that user's RLS policies — exactly as if the user had logged into the live app and viewed the same data. There is no separate "API permissions" model to maintain. If you change an RLS policy in the Security tab, both app users and API users immediately see the new behavior.
A single set of RLS policies governs both your front-end app and your Domain API. Configure the rules once, and they automatically apply everywhere.
Typical Domain API Call
Step 1 — log in the user and capture the token:
POST https://your-custom-domain.com/login
Content-Type: application/json
{
"username": "partner@example.com",
"password": "their-password"
}
Step 2 — call any exposed table with the Bearer token:
GET https://your-custom-domain.com/data/orders
Authorization: Bearer {token-from-login}
The response will only contain the orders that this specific user is allowed to see — anything filtered out by an Allow policy, or matched by a Restrict policy, simply will not appear in the result. Hidden or masked fields are also enforced automatically.
Domain API vs the REST API (App Key)
Tadabase has two separate API surfaces, and they treat RLS differently:
| API | Authentication | RLS applies? |
| REST API (api.tadabase.io) | App ID + App Key + App Secret (server-to-server) | No — full administrative access by design |
| Domain API (your custom domain) | User Bearer token (issued by /login) |
Yes — every call is filtered by the user's RLS policies |
Use the REST API for trusted server-to-server work where you intentionally want unrestricted access (imports, scheduled jobs, integrations you control). Use the Domain API whenever an external system or partner is acting as a user and should only see what that user is allowed to see.
When RLS Is Bypassed
RLS is intentionally bypassed in a handful of situations so you can still administer your app:
- Builder mode — when you are inside the Tadabase builder editing your app, you see all records (this is so you can configure components and view data).
- Bypass Roles — users assigned to a role on the table's Bypass Roles list see everything.
- REST API — calls authenticated with App ID/Key/Secret are server-side and unrestricted by design.
- Background jobs — scheduled tasks, automations, and queue jobs run as the system, not as a user.
Everything else — including the live published app, the Domain API, and "View Permissions As" simulations — runs through RLS.
RLS Rollout Checklist
- ☐ Decide whether the table should be App Level, API Level, or Both
- ☐ Add at least one Allow policy so legitimate users can still see records
- ☐ Pick Bypass Roles for admins who need full access
- ☐ Use View Permissions As to simulate each role and at least one real user
- ☐ Confirm that field-level rules hide or mask sensitive fields correctly
- ☐ If exposing the table over the Domain API, also enable Allow RLS Permission for API Access on the Users table and configure Who can use this API?
- ☐ Test from a fresh browser session as a non-bypass user before announcing the change
We'd love to hear your feedback.