What Is Supabase?
Supabase is an open source Firebase alternative built on PostgreSQL. It provides a hosted Postgres database with a RESTful API (via PostgREST), real-time subscriptions, authentication, file storage, and edge functions — all accessible through a single SDK.
Unlike Firebase (which uses a proprietary NoSQL store), Supabase gives you a real relational database. You can run complex SQL queries, use foreign keys, add custom functions, and even connect your own Postgres client directly.
Setting Up Supabase
# Install the client SDK
npm install @supabase/supabase-js
# Initialize the client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
Get your URL and anon key from the Supabase dashboard under Project Settings → API. The anon key is safe to expose client-side — Row Level Security (RLS) controls what users can actually access.
Database Operations
// SELECT
const { data, error } = await supabase
.from('posts')
.select('id, title, created_at, author:profiles(name)')
.eq('published', true)
.order('created_at', { ascending: false })
.limit(10)
// INSERT
const { data, error } = await supabase
.from('posts')
.insert({ title: 'Hello World', body: '...', user_id: user.id })
.select()
// UPDATE
const { error } = await supabase
.from('posts')
.update({ published: true })
.eq('id', postId)
.eq('user_id', user.id) // RLS-safe pattern
// DELETE
const { error } = await supabase
.from('posts')
.delete()
.eq('id', postId)
Authentication
// Email/password sign up
const { data, error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'password123',
})
// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'password123',
})
// OAuth (Google, GitHub, etc.)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
// Get current user
const { data: { user } } = await supabase.auth.getUser()
// Listen for auth changes
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') setUser(session?.user)
if (event === 'SIGNED_OUT') setUser(null)
})
Row Level Security (RLS)
RLS is the critical security layer that prevents users from reading or modifying each other's data. Enable it on every table and define policies:
-- Enable RLS on the posts table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Users can only read their own posts
CREATE POLICY "Users can read own posts" ON posts
FOR SELECT USING (auth.uid() = user_id);
-- Users can only insert posts for themselves
CREATE POLICY "Users can insert own posts" ON posts
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Public posts are readable by everyone
CREATE POLICY "Public posts are readable" ON posts
FOR SELECT USING (published = true);
Realtime Subscriptions
// Subscribe to changes on a table
const channel = supabase
.channel('posts-changes')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => {
console.log('Change received:', payload)
if (payload.eventType === 'INSERT') setPosts(p => [...p, payload.new])
if (payload.eventType === 'DELETE') setPosts(p => p.filter(post => post.id !== payload.old.id))
}
)
.subscribe()
// Cleanup
return () => supabase.removeChannel(channel)
Frequently Asked Questions
Is Supabase free?
The free tier includes 2 projects, 500MB database, 5GB bandwidth, and 1GB file storage. Paid plans start at $25/month for production workloads. Self-hosting is always free.
Can I run Supabase locally?
Yes. The Supabase CLI spins up a local Docker stack: supabase init && supabase start. This includes Postgres, Auth, Storage, and a local Studio dashboard at http://localhost:54323.
How does Supabase compare to PlanetScale?
PlanetScale is MySQL-based with a focus on horizontal scaling and schema branching. Supabase is Postgres-based with a broader feature set (auth, realtime, storage). Choose Supabase for full-stack apps; PlanetScale for database-only with advanced MySQL features.