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:

  1. Every query through the Supabase API is executed with the role of the requesting user (determined by the JWT).
  2. PostgreSQL evaluates each row against the defined policies.
  3. 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

  1. Select a table and click New Policy.
  2. Choose a creation method:
    • Use a template — start from a common pattern (see below)
    • Custom policy — write the policy from scratch
  3. Enter a policy name (descriptive, e.g., “Users can read own data”).
  4. Select the operation: SELECT, INSERT, UPDATE, DELETE, or ALL.
  5. Select the target role: anon, authenticated, or a custom role.
  6. Enter the USING expression (for row filtering on read/update/delete).
  7. Enter the WITH CHECK expression (for row validation on insert/update).
  8. 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 true as 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

  1. Select a policy from the table’s policy list.
  2. Click Edit to modify the policy.
  3. Update the name, operation, role, USING expression, or WITH CHECK expression.
  4. Click Save to apply changes.

Policy changes take effect immediately.

Deleting Policies

  1. Select a policy from the list.
  2. Click Delete.
  3. 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:

  1. Create a Stackpane connection using the anon key (which respects RLS).
  2. Browse the table and confirm that only the expected rows are visible.
  3. Attempt to insert, update, or delete rows and verify the behavior matches your policy definitions.
  4. 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