TL;DR: Supabase is a hosted platform that gives you PostgreSQL, user authentication, file storage, and real-time subscriptions with a single setup. You connect to it from your frontend or backend using a JavaScript SDK. It is ideal for vibe coders because you skip building a backend from scratch — but you must enable Row Level Security (RLS) or your data is publicly accessible to all authenticated users.
Why AI Coders Need to Know This
Supabase reached 100,000 databases hosted in 2024 and is growing at roughly 10% month-over-month. In the AI coding ecosystem, it has become the de facto recommendation for "I need a database, auth, and storage without running a server." Every major AI coding tool — Cursor, Claude Code, Windsurf, Bolt — generates Supabase integration code as a first-class option.
Supabase bundles five capabilities into one platform:
- PostgreSQL database — Full relational database with SQL, indexes, foreign keys, and triggers
- Authentication — Email/password, magic links, OAuth (Google, GitHub, etc.), phone auth
- File storage — S3-compatible bucket storage with access controls
- Real-time subscriptions — Listen to database changes over WebSocket
- Auto-generated REST and GraphQL APIs — Instant APIs from your schema without writing routes
For a vibe coder building a SaaS MVP, this is a major accelerator: instead of setting up a database, writing auth, configuring file uploads, and building API endpoints separately, Supabase provides all four from a single dashboard.
The critical caveat: Supabase requires understanding Row Level Security (RLS). Without it, your data is accessible to anyone with a valid JWT. AI often forgets to explain this.
Real Scenario
You want to build a simple SaaS app where users can sign up, create projects, and upload files. You want a database, auth, and storage without running a server.
Prompt I Would Type
Set up Supabase for a project management SaaS:
- User auth (email/password + Google OAuth)
- Projects table (id, name, user_id, created_at)
- File storage for project attachments
- Row Level Security so users can only see their own projects
- Show me the client setup and example queries
- What are the security settings I must configure?
What AI Generated
// lib/supabase.ts — client setup
import { createBrowserClient } from '@supabase/ssr';
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
// SQL to run in Supabase dashboard > SQL Editor
CREATE TABLE projects (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name TEXT NOT NULL,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Enable Row Level Security (CRITICAL)
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
-- Policy: users can only see their own projects
CREATE POLICY "Users can view own projects"
ON projects FOR SELECT
USING (auth.uid() = user_id);
-- Policy: users can only insert their own projects
CREATE POLICY "Users can insert own projects"
ON projects FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Policy: users can only update their own projects
CREATE POLICY "Users can update own projects"
ON projects FOR UPDATE
USING (auth.uid() = user_id);
// app/projects/page.tsx — fetch user's projects
import { createClient } from '@/lib/supabase';
export default async function ProjectsPage() {
const supabase = createClient();
// RLS automatically filters to the current user's projects
const { data: projects, error } = await supabase
.from('projects')
.select('*')
.order('created_at', { ascending: false });
if (error) console.error(error);
return (
<ul>
{projects?.map(project => (
<li key={project.id}>{project.name}</li>
))}
</ul>
);
}
// Create a project
async function createProject(name: string) {
const supabase = createClient();
const { data: { user } } = await supabase.auth.getUser();
const { data, error } = await supabase
.from('projects')
.insert({ name, user_id: user?.id })
.select()
.single();
return { data, error };
}
// Upload a file to storage
async function uploadFile(projectId: string, file: File) {
const supabase = createClient();
const path = `projects/${projectId}/${file.name}`;
const { data, error } = await supabase.storage
.from('attachments') // Bucket name
.upload(path, file);
return { data, error };
}
Understanding Each Part
The anon key vs. service role key
Supabase gives you two API keys:
- anon key (
NEXT_PUBLIC_SUPABASE_ANON_KEY) — Safe to use in the browser. Subject to RLS policies. This is what your frontend uses. - service_role key — Bypasses all RLS. Never expose this to the browser. Only use server-side for admin operations.
AI sometimes puts the service_role key in frontend code. This is a critical security mistake — anyone who visits your site can inspect the source and find it, giving them full read/write access to your entire database.
Row Level Security (RLS)
RLS is PostgreSQL's built-in access control at the row level. When enabled, the database checks your policies before returning any data. auth.uid() returns the current user's ID from their JWT — so USING (auth.uid() = user_id) means "only return rows where this user is the owner."
Without RLS, any authenticated user can query any table through the auto-generated API and see all rows. This is the most common Supabase security mistake and the source of several high-profile data leaks.
Supabase vs. Firebase
Supabase
PostgreSQL (relational, SQL)
Open-source (self-host possible)
Strong with complex queries
RLS for row-level security
Better for structured data
Firebase
Firestore (NoSQL, document)
Google proprietary
Better offline/sync support
Security Rules (different model)
Better for mobile-first apps
For vibe coders building web apps with SQL data, Supabase is usually the better choice. For mobile apps with offline-first requirements, Firebase's strengths are more relevant.
The JavaScript client
The @supabase/supabase-js client provides a query builder that generates SQL-safe parameterized queries. .from('projects').select('*').eq('id', projectId) generates SELECT * FROM projects WHERE id = $1 — fully parameterized, safe from SQL injection.
What AI Gets Wrong About Supabase
Forgetting to enable RLS
Creating a table without ALTER TABLE x ENABLE ROW LEVEL SECURITY means all authenticated users can access all rows. AI creates tables frequently without this step. Always check the Supabase dashboard under Authentication > Policies after AI generates database code.
Using the service_role key in the browser
The second-most critical mistake. The service key bypasses all security. It must only exist on the server, in environment variables that are not prefixed with NEXT_PUBLIC_.
Not handling auth state properly
AI generates components that assume the user is always logged in. Add loading states and redirects for unauthenticated users using Supabase's onAuthStateChange or middleware-based auth checks.
Storage bucket permissions
New Supabase storage buckets are private by default. AI sometimes generates file upload code without configuring bucket policies, so uploads succeed but files cannot be read back.
The Supabase Security Checklist
Before shipping any Supabase app: (1) RLS enabled on every table, (2) policies created for each operation, (3) service_role key never in frontend code, (4) storage bucket policies configured, (5) auth redirect URLs whitelisted in dashboard.
What to Learn Next
- What Is PostgreSQL? — Supabase is PostgreSQL under the hood.
- What Is SQL? — Supabase lets you write raw SQL for complex queries.
- What Is Authentication? — Understand the auth concepts Supabase implements.
- Security Basics for AI Coders — RLS is one part of the full security picture.
Next Step
Create a free Supabase project, create a table, and immediately run ALTER TABLE your_table ENABLE ROW LEVEL SECURITY. Then add a policy. Do this before writing a single line of app code — retrofitting RLS is harder than starting with it.
FAQ
Supabase is an open-source Firebase alternative that bundles PostgreSQL, user authentication, file storage, real-time subscriptions, and auto-generated APIs into one hosted platform. It lets vibe coders add a full backend to their apps without building one from scratch.
Yes. Supabase's free tier includes 500 MB database, 1 GB file storage, 50,000 monthly active users for auth, and 2 free projects. This is sufficient for most personal projects and early-stage apps. Paid plans start at $25/month for production workloads.
Supabase uses PostgreSQL (relational) while Firebase uses Firestore (NoSQL). For structured data with complex queries, Supabase is usually better. Firebase has stronger offline sync and is better for mobile-first apps. For most vibe coder web app projects, Supabase's SQL foundation is a significant advantage.
Row Level Security (RLS) is a PostgreSQL feature that controls which database rows each user can access. Supabase uses it to restrict the auto-generated API so users can only see their own data. Without RLS, any authenticated user can read all rows in a table through Supabase's API.
Yes, and it is a very popular pairing. Supabase provides the @supabase/ssr package specifically for Next.js, supporting Server Components, App Router, middleware auth, and edge functions. Most AI tools default to the Supabase + Next.js combination when asked to build a full-stack app.