Supabase 101
Supabase gives you a Postgres database, auth, edge functions, and real-time subscriptions — all in one platform. It replaces five separate services and is the foundation of your entire AI stack.
Why Supabase Is the Foundation
Most backend setups require stitching together a database (RDS), authentication (Auth0), serverless functions (Lambda), real-time features (Pusher), and file storage (S3). Supabase bundles all of these into one platform built on Postgres — the most battle-tested database in existence.
For AI applications specifically, Supabase adds pgvector — a Postgres extension that stores AI embeddings (numerical representations of text meaning) and enables semantic search. This means your AI agent can find memories by meaning, not just keywords.
Two Keys, Two Levels of Access
When you create a Supabase project, you get two API keys. Understanding the difference between them is the most important security concept in this entire course.
Safe for frontend. Can be seen in browser source code. Designed to be public. RLS policies control what it can access — without policies, it can access nothing.
Server-side ONLY. Bypasses ALL RLS. Full access to every table, every row. If this key leaks, your entire database is compromised.
Step-by-Step: Create Your First Project
Follow these steps to go from zero to a working Supabase project with a table, RLS, and your first data.
Create the brain_context Table
This table stores your AI agent's memory as key-value pairs. It is the single most important table in any AI application — the agent's persistent brain.
-- Enable the vector extension for AI embeddings
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE brain_context (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
key text UNIQUE NOT NULL, -- dot notation: 'identity.name'
value jsonb, -- flexible structured data
category text DEFAULT 'general', -- session, directive, system
description text, -- human-readable note
embedding vector(384), -- BGE-small AI embeddings
priority int DEFAULT 5,
updated_at timestamptz DEFAULT now()
);
-- Fast lookups by key
CREATE INDEX idx_brain_key ON brain_context(key);
CREATE INDEX idx_brain_category ON brain_context(category);
-- Semantic search index (cosine similarity)
CREATE INDEX idx_brain_embedding
ON brain_context
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
key uses dot notation (identity.name, session.active_work) for organization. value is JSONB — a binary JSON format that supports indexing and querying inside the structure. embedding stores 384 numbers representing the semantic meaning of the key's content (for AI search).
Enable Row Level Security
RLS is the bouncer for your database. Without it, anyone with your anon key can read all data. With it, the database itself enforces who can see what — even if your application code has bugs.
-- Enable RLS — default-deny: nobody can access without a policy
ALTER TABLE brain_context ENABLE ROW LEVEL SECURITY;
-- Allow the service role (backend only) full access
CREATE POLICY "service_role_all" ON brain_context
FOR ALL TO service_role
USING (true);
-- The anon key (frontend) gets NOTHING by default
-- Add more policies later if users need direct access
Essential SQL Queries
Run these in the Supabase SQL Editor. They cover the four operations you will use constantly: read, write, update, and filter.
-- READ: Fetch all rows (most recent first)
SELECT key, value, updated_at
FROM brain_context
ORDER BY updated_at DESC;
-- WRITE: Insert a new key-value pair
INSERT INTO brain_context (key, value, category)
VALUES ('identity.name', '"AI Stack Builder Student"', 'identity');
-- UPSERT: Write or update (no need to check if key exists)
INSERT INTO brain_context (key, value, category)
VALUES ('session.active_work', '{"task":"building"}', 'session')
ON CONFLICT (key) DO UPDATE SET
value = EXCLUDED.value,
updated_at = now();
-- FILTER: Find all session keys
SELECT key, value FROM brain_context
WHERE key LIKE 'session.%';
Supabase Client: JavaScript SDK
In production, you interact with Supabase through the JavaScript SDK — not raw SQL. The SDK provides type-safe methods for every operation.
import { createClient } from '@supabase/supabase-js'
// Initialize (these are safe for the frontend)
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
// READ — Fetch the 10 most recently updated brain keys
const { data, error } = await supabase
.from('brain_context')
.select('key, value, updated_at')
.order('updated_at', { ascending: false })
.limit(10)
// UPSERT — Write or update a key-value pair
const { error: writeErr } = await supabase
.from('brain_context')
.upsert({
key: 'session.active_work',
value: { task: 'Building the AI stack', status: 'in_progress' }
}, { onConflict: 'key' })
// FILTER — Find all keys matching a pattern
const { data: sessions } = await supabase
.from('brain_context')
.select('*')
.like('key', 'session.%')
The Five Superpowers of Supabase
Each of these replaces a separate service you would otherwise need to set up, configure, and maintain independently.
| Feature | What It Does | Replaces |
|---|---|---|
| Postgres Database | Full SQL database with JSONB, views, triggers, and 30+ years of reliability | AWS RDS, PlanetScale, MongoDB |
| Auth + RLS | User signup/login, JWT tokens, row-level access control | Auth0, Firebase Auth, Clerk |
| Edge Functions | Serverless TypeScript functions deployed globally (Deno runtime) | AWS Lambda, Cloudflare Workers |
| Realtime | Live subscriptions — your UI updates instantly when data changes | Pusher, Socket.io, Firebase Realtime |
| pgvector | Store AI embeddings, search by semantic meaning | Pinecone, Weaviate, Chroma |