Supabase architecture (Postgres, Auth, Storage, Realtime, Edge Functions) - Time & Space Complexity
We want to understand how the work done by Supabase services grows as more users or data are involved.
How does the number of operations change when we use Postgres, Auth, Storage, Realtime, and Edge Functions together?
Analyze the time complexity of the following operation sequence.
// User signs up
const { data, error } = await supabase.auth.signUp({ email, password })
// User uploads a file
const { data: fileData, error: fileError } = await supabase.storage
.from('avatars')
.upload('public/avatar1.png', file)
// User fetches messages in realtime
const subscription = supabase
.from('messages')
.on('INSERT', payload => console.log('New message:', payload))
.subscribe()
// User calls an edge function
const response = await supabase.functions.invoke('hello-world')
This sequence shows a user signing up, uploading a file, listening for new messages, and calling a serverless function.
Identify the API calls, resource provisioning, data transfers that repeat.
- Primary operation: API calls to Supabase services (Auth, Storage, Realtime, Edge Functions)
- How many times: Each user action triggers one or more calls; Realtime subscription listens continuously for new events
As more users sign up and upload files, the number of API calls grows roughly with the number of users.
| Input Size (n users) | Approx. Api Calls/Operations |
|---|---|
| 10 | ~10 sign-ups + 10 uploads + 10 edge calls + ongoing realtime events |
| 100 | ~100 sign-ups + 100 uploads + 100 edge calls + ongoing realtime events |
| 1000 | ~1000 sign-ups + 1000 uploads + 1000 edge calls + ongoing realtime events |
Pattern observation: The number of operations grows linearly with the number of users and their actions.
Time Complexity: O(n)
This means the total work grows directly in proportion to the number of users and their actions.
[X] Wrong: "Realtime subscriptions cause the system to do the same work regardless of user count."
[OK] Correct: Each active subscription listens and processes events, so more users mean more ongoing work.
Understanding how service calls grow with users helps you design scalable apps and explain your architecture choices clearly.
"What if we batch user uploads instead of uploading one file at a time? How would the time complexity change?"
Practice
Solution
Step 1: Understand Supabase components
Supabase has several parts: Postgres for data, Auth for users, Storage for files, Realtime for live updates, and Edge Functions for custom code.Step 2: Identify user management part
The component that handles user sign-ups, logins, and authentication is called Auth.Final Answer:
Auth -> Option DQuick Check:
User management = Auth [OK]
- Confusing Postgres with user management
- Thinking Storage handles users
- Mixing Realtime with authentication
Solution
Step 1: Recall Supabase client initialization syntax
Supabase uses the function createClient(url, key) to create a client instance.Step 2: Match correct syntax
const supabase = createClient('url', 'anon_key'); matches the exact syntax: const supabase = createClient('url', 'anon_key');Final Answer:
const supabase = createClient('url', 'anon_key'); -> Option BQuick Check:
Use createClient() to initialize Supabase [OK]
- Using new keyword with Supabase
- Calling wrong function names
- Mixing class and function syntax
const subscription = supabase
.from('messages')
.on('INSERT', payload => {
console.log('New message:', payload.new.text);
})
.subscribe();Solution
Step 1: Understand Realtime subscription
The code listens for INSERT events on the 'messages' table and logs the new row's text field.Step 2: Analyze the callback behavior
When a new row is inserted, payload.new contains the new row data, so payload.new.text is the inserted message text.Final Answer:
New message: [text of inserted row] -> Option AQuick Check:
Realtime INSERT event logs new row text [OK]
- Expecting payload.old instead of payload.new
- Thinking .subscribe() is invalid
- Assuming no output on INSERT
export async function POST(request) {
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);
const data = await request.formData();
const file = data.get('file');
const { error } = await supabase.storage.from('avatars').upload(file.name, file);
if (error) return new Response(error.message, { status: 400 });
return new Response('Upload successful');
}Solution
Step 1: Check authentication context for storage upload
Storage upload requires a user session or proper auth context; using service role key alone in Edge Functions does not provide user session.Step 2: Identify missing user session
Without user session, storage upload is denied due to permission error.Final Answer:
Storage upload requires user session, missing auth -> Option AQuick Check:
Storage upload needs user auth session [OK]
- Assuming service role key works for storage upload
- Ignoring bucket existence
- Not checking file extraction from formData
Solution
Step 1: Identify storage needs
Messages are structured data best stored in Postgres; avatars are files stored in Storage.Step 2: Identify live update and user management
Realtime provides live updates for messages; Auth manages user login.Final Answer:
Postgres for messages, Storage for avatars, Realtime for live updates, Auth for user login -> Option CQuick Check:
Use Postgres, Storage, Realtime, Auth together [OK]
- Mixing Storage with live updates
- Using Realtime for file storage
- Confusing Auth with data storage
Ready to prove it?
Pass the test and this pattern moves unknown
