Row-Level Security
View, create, and manage Supabase Row-Level Security policies for fine-grained table access control.
Overview
Row-Level Security (RLS) is a PostgreSQL feature that restricts which rows a user can access in a table. Supabase relies on RLS as its primary access control mechanism — when enabled on a table, every query is filtered through the defined policies. Stackpane provides a visual interface for managing RLS policies without writing raw SQL.
How RLS Works in Supabase
When RLS is enabled on a table:
- Every query through the Supabase API is executed with the role of the requesting user (determined by the JWT).
- PostgreSQL evaluates each row against the defined policies.
- Only rows that pass at least one applicable policy are returned or modified.
If no policies are defined on a table with RLS enabled, no rows are accessible — this is a deny-by-default model.
The anon role applies to unauthenticated requests. The authenticated role applies to requests with a valid user JWT. The service_role key bypasses RLS entirely.
Viewing Policies
Navigate to the Row-Level Security section from the sidebar, or access it from a table’s context menu.
Per-Table View
Select a table to see all its RLS policies displayed in a list:
- Policy name — the descriptive name of the policy
- Operation — which operations the policy applies to (SELECT, INSERT, UPDATE, DELETE, or ALL)
- Role — which database roles the policy targets (e.g.,
anon,authenticated,public) - USING expression — the SQL expression evaluated for existing rows (read/update/delete operations)
- WITH CHECK expression — the SQL expression evaluated for new or modified rows (insert/update operations)
RLS Status
Each table shows whether RLS is enabled or disabled. Tables without RLS enabled allow unrestricted access through the API, which is a security risk in production.
Creating Policies
- Select a table and click New Policy.
- Choose a creation method:
- Use a template — start from a common pattern (see below)
- Custom policy — write the policy from scratch
- Enter a policy name (descriptive, e.g., “Users can read own data”).
- Select the operation: SELECT, INSERT, UPDATE, DELETE, or ALL.
- Select the target role:
anon,authenticated, or a custom role. - Enter the USING expression (for row filtering on read/update/delete).
- Enter the WITH CHECK expression (for row validation on insert/update).
- Click Create.
The policy takes effect immediately for all API requests.
Policy Templates
Stackpane provides built-in templates for common RLS patterns, generated by SupabaseRLSSQLBuilder:
Owner-Based Access
Allow users to access only rows where a column matches their user ID:
auth.uid() = user_id
Select the column that stores the user’s UUID (commonly user_id, owner_id, or created_by).
Public Read, Authenticated Write
Allow anyone to read, but only authenticated users can insert or modify:
- SELECT policy with
trueas the USING expression (allows all reads) - INSERT/UPDATE/DELETE policy with
auth.role() = 'authenticated'as the expression
Admin Bypass
Allow users with an admin flag in their JWT claims to access all rows:
auth.jwt() -> 'app_metadata' ->> 'role' = 'admin'
Team-Based Access
Allow users to access rows belonging to their team:
team_id IN (
SELECT team_id FROM team_members
WHERE user_id = auth.uid()
)
Editing Policies
- Select a policy from the table’s policy list.
- Click Edit to modify the policy.
- Update the name, operation, role, USING expression, or WITH CHECK expression.
- Click Save to apply changes.
Policy changes take effect immediately.
Deleting Policies
- Select a policy from the list.
- Click Delete.
- Confirm the deletion in the dialog.
Deleting a policy may immediately restrict or grant access to rows, depending on the remaining policies. Review the impact before confirming.
Enabling and Disabling RLS
Toggle RLS for a table from the table info panel:
- Enable RLS — activates row-level security. If no policies exist, all access is denied by default.
- Disable RLS — deactivates row-level security. All rows become accessible to any role through the API.
Disabling RLS on a production table is a security risk and should only be done temporarily for debugging.
Testing Policies
To verify that your policies work correctly:
- Create a Stackpane connection using the anon key (which respects RLS).
- Browse the table and confirm that only the expected rows are visible.
- Attempt to insert, update, or delete rows and verify the behavior matches your policy definitions.
- Compare with a service role key connection (which bypasses RLS) to see the full dataset.
This dual-connection approach lets you quickly validate RLS behavior without writing test code.
Tips
- Always enable RLS on tables that are accessible through the Supabase API
- Start with restrictive policies and relax them as needed — deny-by-default is safer
- Use the
auth.uid()function to scope policies to the current user - Test policies with the anon key connection to simulate real client behavior
- Name policies descriptively so their purpose is clear when reviewing the list
- Remember that the service role key bypasses RLS entirely — do not use it in client applications