Claude
Skills
Sign in
Back

Supabase Developer

Included with Lifetime
$97 forever

Build full-stack applications with Supabase (PostgreSQL, Auth, Storage, Real-time, Edge Functions). Use when implementing authentication, database design with RLS, file storage, real-time features, or serverless functions.

backendbackenddatabaseauthenticationstoragereal-timeserverless

What this skill does


# Supabase Developer

**Build production-ready full-stack applications with Supabase.**

Supabase is an open-source Firebase alternative providing PostgreSQL database, authentication, storage, real-time subscriptions, and edge functions. This skill guides you through building secure, scalable applications using Supabase's full feature set.

---

## When to Use This Skill

- **Authentication**: Implementing user signup/login with email, OAuth, magic links, or phone auth
- **Database**: Designing PostgreSQL schemas with Row Level Security (RLS)
- **Storage**: Managing file uploads, downloads, and access control
- **Real-time**: Building live features with subscriptions and broadcasts
- **Edge Functions**: Serverless TypeScript functions at the edge
- **Migrations**: Managing database schema changes
- **Integration**: Connecting Next.js, React, Vue, or other frameworks

---

## Core Supabase Concepts

### 1. Database (PostgreSQL)

Supabase uses PostgreSQL with extensions:

- **PostgREST**: Auto-generates REST API from schema
- **pg_graphql**: Optional GraphQL support
- **Extensions**: pgvector for embeddings, pg_cron for scheduled jobs

### 2. Authentication

Built-in auth with multiple providers:

- Email/password with confirmation
- Magic links (passwordless)
- OAuth (Google, GitHub, etc.)
- Phone/SMS authentication
- SAML SSO (enterprise)

### 3. Row Level Security (RLS)

PostgreSQL policies that enforce data access at the database level:

- User can only read their own data
- Admin can read all data
- Public read, authenticated write

### 4. Storage

S3-compatible object storage with RLS:

- Public and private buckets
- File size and type restrictions
- Image transformations on the fly
- CDN integration

### 5. Real-time

WebSocket-based subscriptions:

- Database changes (INSERT, UPDATE, DELETE)
- Broadcast messages to channels
- Presence tracking (who's online)

### 6. Edge Functions

Deno-based serverless functions:

- Deploy globally at the edge
- TypeScript/JavaScript runtime
- Background jobs and webhooks
- Custom API endpoints

---

## 6-Phase Supabase Implementation

### Phase 1: Project Setup & Configuration

**Goal**: Initialize Supabase project and connect to your application

#### 1.1 Create Supabase Project

```bash
# Option A: Web Dashboard
# 1. Go to https://supabase.com
# 2. Create new project
# 3. Save database password securely

# Option B: CLI (recommended for production)
npx supabase init
npx supabase start
```

#### 1.2 Install Client Libraries

```bash
# JavaScript/TypeScript
npm install @supabase/supabase-js

# React helpers (optional)
npm install @supabase/auth-helpers-react @supabase/auth-helpers-nextjs

# For Auth UI components
npm install @supabase/auth-ui-react @supabase/auth-ui-shared
```

#### 1.3 Environment Configuration

```env
# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key # Server-side only!
```

#### 1.4 Initialize Client

```typescript
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```

**Next.js 13+ App Router Pattern:**

```typescript
// lib/supabase/client.ts (Client Components)
import { createBrowserClient } from '@supabase/ssr'

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}

// lib/supabase/server.ts (Server Components)
import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { cookies } from 'next/headers'

export function createClient() {
  const cookieStore = cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return cookieStore.get(name)?.value
        }
      }
    }
  )
}
```

---

### Phase 2: Authentication Implementation

**Goal**: Secure user authentication with session management

#### 2.1 Authentication Strategies

**Email/Password Authentication:**

```typescript
// Sign up
async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
    options: {
      emailRedirectTo: 'https://yourapp.com/auth/callback'
    }
  })

  if (error) throw error
  return data
}

// Sign in
async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password
  })

  if (error) throw error
  return data
}

// Sign out
async function signOut() {
  const { error } = await supabase.auth.signOut()
  if (error) throw error
}
```

**OAuth Authentication:**

```typescript
// Google OAuth
async function signInWithGoogle() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
    options: {
      redirectTo: 'https://yourapp.com/auth/callback',
      queryParams: {
        access_type: 'offline',
        prompt: 'consent'
      }
    }
  })

  if (error) throw error
  return data
}

// GitHub, Twitter, Discord, etc. - same pattern
```

**Magic Link (Passwordless):**

```typescript
async function signInWithMagicLink(email: string) {
  const { data, error } = await supabase.auth.signInWithOtp({
    email,
    options: {
      emailRedirectTo: 'https://yourapp.com/auth/callback'
    }
  })

  if (error) throw error
  return data
}
```

#### 2.2 Session Management

```typescript
// Get current session
async function getSession() {
  const {
    data: { session },
    error
  } = await supabase.auth.getSession()
  return session
}

// Get current user
async function getUser() {
  const {
    data: { user },
    error
  } = await supabase.auth.getUser()
  return user
}

// Listen to auth changes
supabase.auth.onAuthStateChange((event, session) => {
  console.log(event, session)

  if (event === 'SIGNED_IN') {
    // User signed in
  }
  if (event === 'SIGNED_OUT') {
    // User signed out
  }
  if (event === 'TOKEN_REFRESHED') {
    // Token refreshed
  }
})
```

#### 2.3 Protected Routes (Next.js)

```typescript
// middleware.ts
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(req: NextRequest) {
  const res = NextResponse.next()
  const supabase = createMiddlewareClient({ req, res })

  const {
    data: { session }
  } = await supabase.auth.getSession()

  // Protected routes
  if (!session && req.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', req.url))
  }

  return res
}

export const config = {
  matcher: ['/dashboard/:path*', '/profile/:path*']
}
```

---

### Phase 3: Database Design & RLS

**Goal**: Design secure database schema with Row Level Security

#### 3.1 Schema Design

```sql
-- Example: Blog application schema

-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Profiles table (extends auth.users)
CREATE TABLE profiles (
  id UUID REFERENCES auth.users(id) PRIMARY KEY,
  username TEXT UNIQUE NOT NULL,
  full_name TEXT,
  avatar_url TEXT,
  bio TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Posts table
CREATE TABLE posts (
  id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
  user_id UUID REFERENCES profiles(id) ON DELETE CASCADE NOT NULL,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  published BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Comments table
CREATE TABLE comments (
  id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
  post_id UUID REFERENCES post

Related in backend