Supabase + Claude Code: the complete guide to AI-assisted full-stack development
A practical guide to building a production-ready full-stack app with Supabase and Claude Code: auth, database design, Row Level Security, edge functions, and real-time — all with working Claude Code prompts.
By CB Patel
Supabase (Postgres + Auth + Storage + Edge Functions + Realtime) and Claude Code (AI coding agent) pair well. Supabase's SQL-first approach means you can describe what you want in plain English and have the agent translate it to Postgres DDL, RLS policies, and TypeScript types. This guide covers the full stack — from initial schema design to production edge functions.
Why this pairing works
Supabase has excellent documentation, stable TypeScript client APIs, and clear patterns for auth, data, and storage. Compared to setting up custom Express + Postgres + JWT auth manually, this is a significant time saving.
Before you start — install the right skills
for s in nextjs-app-router-pro supabase-fullstack; do curl -fsSL --create-dirs -o .claude/skills/$s/SKILL.md https://claudeskil.com/skills/$s/SKILL.md; done
This gives Claude Code ready-made context for Next.js 14 App Router patterns and for Supabase auth, RLS policies, edge functions, storage, and realtime, loaded whenever a request matches.
Part 1 — Schema design with Claude Code
Don't design your database schema in a UI — describe it to Claude Code and let it generate the SQL.
I'm building a SaaS project management tool. Users can create projects, invite team members, and create tasks within projects. Tasks have a status (todo, in_progress, done), a due date, and can be assigned to one team member. Design the database schema as PostgreSQL DDL. Include: table definitions with correct types and constraints, foreign key relationships, indexes for the most common queries (list tasks by project, list projects by user), and comments explaining non-obvious decisions.
Review the output. Look for:
- UUID vs bigint primary keys (UUID is safer for multi-tenant SaaS)
- Missing indexes on foreign key columns (Postgres doesn't auto-index FKs)
- Cascade behavior on deletes (usually you want cascade for child records, set null for assignments)
Step 2 — Row Level Security (the most important part)
RLS is how Supabase enforces data isolation. Without it, a table in an exposed schema is readable and writable by any role with a grant on it, which by default can include anonymous users holding your project's public key. Claude Code can write RLS policies, but you must verify them.
add Row Level Security policies for all tables. The rules are: users can only see projects they created OR projects they are a team member of (via a project_members table). Users can only see tasks that belong to projects they have access to. Users can only create tasks in projects they have access to.
The generated policies will look like:
create policy "users can view their projects"
on projects for select
using (
created_by = auth.uid() or
exists (
select 1 from project_members
where project_id = projects.id and user_id = auth.uid()
)
);
Test these before shipping. The Supabase dashboard lets you impersonate a user in the Table Editor and SQL Editor, so you can see exactly what that user's policies allow. A common bug: a SELECT policy that's too permissive (missing conditions) or an INSERT policy that doesn't include enough context.
create a test scenario: a user with id '00000000-0000-0000-0000-000000000001' creates a project and a task. a different user with id '00000000-0000-0000-0000-000000000002' tries to select the project. write the SQL test queries I can run in Supabase's SQL editor to verify the RLS policies work correctly.
Step 3 — TypeScript types from your schema
Supabase can generate TypeScript types from your schema. Run:
npx supabase gen types typescript --project-id your-project-id > lib/supabase/types.ts
Then tell Claude Code:
the file lib/supabase/types.ts contains auto-generated Supabase types. Use the Database type and the Row/Insert/Update helpers throughout the codebase. Never manually define types that correspond to database tables.
This prevents the common mistake of hand-writing types that drift out of sync with the schema.
Part 2 — Authentication patterns
set up Supabase Auth for a Next.js 14 App Router app. use the @supabase/ssr package (not the older auth-helpers package). create: lib/supabase/client.ts (browser client), lib/supabase/server.ts (server client using cookies), middleware.ts (session refresh on every request, protect /dashboard/* and /api/v1/* routes). The sign-in page should support GitHub OAuth and magic link.
The critical detail: the @supabase/ssr package requires specific cookie handling for the server client. Verify that lib/supabase/server.ts uses cookies() from next/headers and implements the getAll and setAll methods in the cookies option.
Part 3 — Real-time features
For a task management app:
add real-time task updates to the task list component. when another user updates a task status or adds a comment, the current user's view should update without a page refresh. use supabase.channel() with postgres_changes events. filter to only receive changes for the current project.
Claude Code will generate a useEffect hook that subscribes to Postgres changes. Important: always unsubscribe in the cleanup function or you'll accumulate subscriptions on re-renders. Verify the generated code calls channel.unsubscribe() or supabase.removeChannel() in the useEffect cleanup.
Part 4 — Edge Functions
Supabase Edge Functions run on Deno at the edge. Use them for: webhook handlers, background jobs triggered by database events, and API routes that need to stay close to the database.
create a Supabase Edge Function called on-task-complete. it should be triggered when a task's status changes to 'done'. it should: 1) look up the task and project name, 2) find all project members, 3) send a notification email via Resend to each member except the one who completed the task. use the RESEND_API_KEY environment variable.
Claude Code will create supabase/functions/on-task-complete/index.ts with a Deno-compatible TypeScript implementation. Key difference from Node.js: Edge Functions run on Deno, so fetch is built in (no node-fetch needed), and external modules come in through npm: or jsr: specifiers, URL imports, or a per-function deno.json.
Deploy it:
npx supabase functions deploy on-task-complete
Then create a Database Webhook in the Supabase dashboard for UPDATE events on the tasks table, pointing at the on-task-complete function. Supabase's Database Webhooks guide covers the steps.
Part 5 — Storage
add file attachment support to tasks. users can attach files up to 10MB per task. create a Supabase storage bucket called task-attachments with RLS (users can only access files belonging to tasks in their projects). add an upload function in lib/storage.ts and a file list component in components/task/attachments.tsx.
For the RLS on storage, Claude Code will write storage policies. These use a slightly different syntax than table RLS — verify the generated policies use the storage.objects table and the auth.uid() function correctly.
Production checklist
Before going live, ask Claude Code to audit your Supabase setup:
audit our Supabase integration for production readiness. check: 1) are all tables protected by RLS? 2) are there any security definer functions that bypass RLS unexpectedly? 3) are the API keys we expose client-side only the anon key (never the service_role key)? 4) do we handle auth session expiry gracefully?
The service_role key should never appear in client-side code, .env.local committed to git, or anywhere except server-side environments.
Find more Supabase and full-stack skills at claudeskil.com/category/fullstack and claudeskil.com/category/backend.