Skip to content

Latest commit

 

History

History
148 lines (98 loc) · 5.28 KB

File metadata and controls

148 lines (98 loc) · 5.28 KB

Supabase — Plain English Guide

Supabase is your project's database, login system, and file storage — all in one place. Think of it as three things wrapped together: a spreadsheet (for storing data), a security guard (for controlling who sees what), and a lock system (for user accounts and passwords).

You don't have to build any of this yourself. Supabase does it.


Tables

A table is like a spreadsheet tab. One table for users. One for orders. One for messages. Each row is one record — one user, one order, one message. Each column is one piece of information about that record.

You create and edit tables in the Supabase dashboard under Table Editor — no code needed for the basics.

The most common mistake: Trying to add data before the table exists, or putting data in the wrong table.


Row Level Security (RLS)

What it is: A lock on every single row in every table. When RLS is on and no rules are written, nobody can read or write anything — not even your own app.

Why it exists: Without RLS, anyone who got hold of your Supabase key could read your entire database. RLS makes sure people only see the data they're supposed to.

The two-step trap that gets everyone:

  • Step 1: Turn RLS on (most people do this)
  • Step 2: Write "policies" — rules about who can see and do what (most people skip this and wonder why nothing works)

Setting up basic policies: In the Supabase dashboard: Authentication → Policies → New Policy

Or paste this in the SQL Editor and adjust the table name:

-- Anyone can read (public data)
CREATE POLICY "allow_read" ON your_table
  FOR SELECT USING (true);

-- Only logged-in users can add new rows
CREATE POLICY "allow_insert" ON your_table
  FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);

-- Users can only edit their own rows
CREATE POLICY "allow_update_own" ON your_table
  FOR UPDATE USING (auth.uid() = user_id);

For testing: You can temporarily disable RLS on a table (Table Editor → table → RLS toggle). Never leave it off in production — that means anyone can read everything.


The anon key vs the service_role key

Both are on your Supabase dashboard under Settings → API.

anon key — safe to put in your frontend code. Limited access. Respects your RLS policies. Use this one in React, Next.js, etc.

service_role key — has admin access to everything, bypasses RLS. NEVER put this in frontend code or push it to GitHub. This is for server-side only (backend, edge functions, scripts run on your VPS).

If your service_role key ever shows up in a GitHub commit, rotate it immediately in the Supabase dashboard.


Authentication (Login / Signup)

Supabase Auth handles signups, logins, and password resets — you don't build any of this yourself.

// Let someone sign up
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'their-password'
})

// Let someone log in
const { data, error } = await supabase.auth.signInWithPassword({
  email: 'user@example.com',
  password: 'their-password'
})

// Find out who's logged in right now
const { data: { user } } = await supabase.auth.getUser()

// Log out
await supabase.auth.signOut()

After a user logs in, Supabase automatically attaches their identity to every database request. This is how RLS policies can say "only show this user their own rows" — Supabase knows who's asking.


Edge Functions

Edge Functions are small pieces of server-side code that run on Supabase's servers (not your computer, not Vercel). Use them when you need to do something secretly — like calling an API without your secret key being visible in your frontend code.

Think of them as: a private back room where your app can do things the public website shouldn't.

# Deploy a function
supabase functions deploy function-name

# Call it from your app
const { data, error } = await supabase.functions.invoke('function-name', {
  body: { the: 'data you want to send' }
})

Schema confusion

By default, your tables live in the "public" schema. If you or Claude created a custom schema (like "aridunu", "app", "internal"), two separate steps are needed to make it work:

Step 1: Tell Supabase's API about it Go to: Settings → API → "Extra schemas to expose" → add your schema name

Step 2: Grant access in SQL Editor:

GRANT USAGE ON SCHEMA yourschema TO anon, authenticated;
GRANT ALL ON ALL TABLES IN SCHEMA yourschema TO anon, authenticated;

Skipping either step causes "permission denied for schema" errors. Both steps are required.


Connecting Supabase to your project

You need two things from your Supabase dashboard (Settings → API):

  1. Your Project URL — looks like https://abcdefgh.supabase.co
  2. Your anon key — a long string starting with eyJ...

These go in your .env file:

NEXT_PUBLIC_SUPABASE_URL=https://abcdefgh.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...

Then in your code:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)

On Vercel: These environment variables need to be added in Vercel's dashboard too (Settings → Environment Variables). Your local .env file doesn't automatically go to Vercel.