Select policies for read access in Supabase - Time & Space Complexity
When we set up read access policies in Supabase, we want to know how the time to check these policies changes as we read more data.
We ask: How does the number of policy checks grow when we read more rows?
Analyze the time complexity of the following operation sequence.
const { data, error } = await supabase
.from('messages')
.select('*')
.eq('user_id', currentUser.id)
.limit(50)
This code fetches up to 50 messages belonging to the current user, applying read access policies on each row.
Identify the API calls, resource provisioning, data transfers that repeat.
- Primary operation: Checking read access policy for each row returned.
- How many times: Once per row fetched (up to the limit).
As you ask for more rows, the system checks the policy for each row separately.
| Input Size (n) | Approx. Api Calls/Operations |
|---|---|
| 10 | 10 policy checks |
| 100 | 100 policy checks |
| 1000 | 1000 policy checks |
Pattern observation: The number of policy checks grows directly with the number of rows requested.
Time Complexity: O(n)
This means the time to check read access grows in a straight line as you ask for more rows.
[X] Wrong: "The read access policy is checked only once for the whole query."
[OK] Correct: Each row is checked separately to ensure security for every piece of data returned.
Understanding how policies scale helps you design secure and efficient data access in real projects.
"What if we added a filter that reduces rows before policy checks? How would the time complexity change?"
Practice
SELECT policy in Supabase?Solution
Step 1: Understand the role of SELECT policies
SELECT policies define rules for reading data from tables.Step 2: Differentiate from other policies
Write policies control data insertion or updates, not reading.Final Answer:
To control who can read data from a table -> Option AQuick Check:
SELECT policy = read access control [OK]
- Confusing SELECT with INSERT or UPDATE policies
- Thinking SELECT policies create or delete tables
- Assuming SELECT policies control write access
profiles?Solution
Step 1: Identify the correct command for read access
FOR SELECT is used to allow read (select) operations.Step 2: Confirm the condition for allowing all users
USING (true) means no restriction, so all users can read.Final Answer:
CREATE POLICY "Allow all" ON profiles FOR SELECT USING (true); -> Option CQuick Check:
FOR SELECT + USING (true) = allow all read [OK]
- Using FOR INSERT instead of FOR SELECT
- Forgetting the USING clause
- Using FOR DELETE or UPDATE for read access
CREATE POLICY "User can read own profile" ON profiles FOR SELECT USING (auth.uid() = user_id);
What will happen if a user tries to select a profile where
user_id is different from their auth.uid()?Solution
Step 1: Understand the policy condition
The policy allows reading only if auth.uid() equals user_id.Step 2: Analyze the case when user_id differs
If user_id is different, the condition fails, so no rows are returned.Final Answer:
The user will get an empty result (no rows) -> Option BQuick Check:
Condition false = no rows returned [OK]
- Assuming user can read all profiles
- Expecting an error instead of empty result
- Confusing read with update permissions
CREATE POLICY "Allow read" ON orders FOR SELECT USING (user_id = auth.uid);
But users cannot read their orders. What is the problem?
Solution
Step 1: Check the usage of auth.uid
auth.uid is a function and must be called with parentheses: auth.uid()Step 2: Understand impact of missing parentheses
Without (), the condition is invalid and blocks access.Final Answer:
auth.uid should be called as a function: auth.uid() -> Option DQuick Check:
auth.uid() is required for correct condition [OK]
- Using auth.uid without parentheses
- Confusing FOR SELECT with FOR UPDATE
- Removing USING clause mistakenly
messages table. The table has columns id, content, and owner_id. Which policy correctly enforces this read access?Solution
Step 1: Identify correct condition for own data
Users should read rows where owner_id equals their auth.uid()Step 2: Confirm correct policy type and condition
FOR SELECT with USING (owner_id = auth.uid()) restricts reads properly.Final Answer:
CREATE POLICY "Read own messages" ON messages FOR SELECT USING (owner_id = auth.uid()); -> Option AQuick Check:
owner_id = auth.uid() restricts read to own rows [OK]
- Using != instead of = in condition
- Allowing all reads with USING (true)
- Using FOR UPDATE instead of FOR SELECT
Ready to prove it?
Pass the test and this pattern moves unknown
