# Supabase Sdk Patterns

> | Use when implementing Supabase queries, auth, realtime, storage, or RPC calls with @supabase/supabase-js or supabase-py and you need production-ready, type-safe patterns that always check the { data, error } contract. Trigger with phrases like "supabase SDK patterns", "supabase query", "supabase typescript", "supabase python", "supabase client setup", "supabase realtime", "supabase auth", "supabase storage".

- Skill: `thedixitjain/supabase-sdk-patterns` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds add thedixitjain/supabase-sdk-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thedixitjain/supabase-sdk-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: thedixitjain (https://skillmd.com/u/thedixitjain)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/thedixitjain/supabase-sdk-patterns

---


# Supabase SDK Patterns

## Overview

Production patterns for `@supabase/supabase-js` v2 and `supabase-py`, where every call returns `{ data, error }` and success is never assumed. Covers client initialization, CRUD with filters, auth, realtime, storage, and RPC, with Python equivalents for the query patterns.

## Prerequisites

- Supabase project with URL and anon key (or service role key for server-side)
- `@supabase/supabase-js` v2 installed (TypeScript) or `supabase` pip package (Python)
- TypeScript projects: generated database types via `supabase gen types typescript`

## Instructions

### Step 1: Initialize a typed singleton client

Create one client instance and reuse it. Never call `createClient` per-request — a
singleton preserves the auth session and connection pool.

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

let supabase: ReturnType<typeof createClient<Database>>

export function getSupabase() {
  if (!supabase) {
    supabase = createClient<Database>(
      process.env.SUPABASE_URL!,
      process.env.SUPABASE_ANON_KEY!,
      {
        auth: { autoRefreshToken: true, persistSession: true },
        db: { schema: 'public' },
        global: { headers: { 'x-app-name': 'my-app' } },
      }
    )
  }
  return supabase
}
```

**Python equivalent:**

```python
from supabase import create_client, Client

_client: Client | None = None

def get_supabase() -> Client:
    global _client
    if _client is None:
        _client = create_client(
            os.environ["SUPABASE_URL"],
            os.environ["SUPABASE_ANON_KEY"],
        )
    return _client
```

### Step 2: Query, filter, and mutate data

Destructure `{ data, error }` and check `error` before touching `data`. Chain
filters onto `.from(table).select(...)`; use `.select().single()` after an
insert/upsert to return the affected row. Skeleton:

```typescript
const { data, error } = await getSupabase()
  .from('users')
  .select('id, name, email')
  .eq('active', true)
  .order('name')
  .limit(10)

if (error) throw error
```

For the full CRUD set (insert-with-select, upsert on conflict, update, delete,
RPC), the complete 12-filter reference table, and the Python equivalents, see
[queries and filters](references/queries-and-filters.md).

### Step 3: Auth, realtime, and storage

Auth, realtime channels, and storage all follow the same `{ data, error }`
contract. Auth exposes `signUp` / `signInWithPassword` / `getSession` /
`onAuthStateChange`; realtime subscribes to `postgres_changes` on a channel and
requires `removeChannel` cleanup; storage does `upload` / `download` /
`getPublicUrl` / `createSignedUrl` per bucket. Full walkthroughs with code for
each: see [auth, realtime, and storage](references/auth-realtime-storage.md).

## Output

Applying these patterns yields:

- Type-safe singleton client with `Database` generics
- CRUD operations using the full filter chain (eq, gt, in, ilike, etc.)
- Insert-with-select and upsert patterns that return the affected row
- Auth flows for sign-up, sign-in, session management, and state listeners
- Realtime subscriptions with row-level filtering and cleanup
- Storage upload/download with signed URLs for private buckets
- Python equivalents for the query patterns

## Error Handling

Every Supabase call returns `{ data, error }`. Never skip the error check.

```typescript
const { data, error } = await getSupabase().from('users').select('*')

if (error) {
  // error is a PostgrestError with these fields:
  //   error.message  — human-readable description
  //   error.code     — Postgres error code (e.g., '23505')
  //   error.details  — additional context
  //   error.hint     — suggested fix from Postgres
  console.error(`Query failed [${error.code}]: ${error.message}`)
  throw error
}

// Only safe to use data after the error check
```

| Error Code | Meaning | What to Do |
| ------------ | --------- | ------------ |
| `PGRST116` | No rows found (`.single()`) | Return null or 404, don't throw |
| `23505` | Unique-constraint violation (Postgres duplicate key) | Use `.upsert()` or show conflict error |
| `42501` | RLS policy violation (Postgres insufficient privilege) | Check auth state and RLS policies |
| `PGRST000` | Connection error | Retry with exponential backoff |
| `42P01` | Table does not exist | Verify table name and run migrations |
| `23503` | Foreign key violation | Ensure referenced row exists first |
| `42703` | Column does not exist | Check column name, regenerate types |

## Examples

The recommended production shape is a typed **service layer** that wraps the
client so callers never touch raw queries, plus a **pagination helper** that
returns a page of rows and the total count in one round trip. Both full,
copy-ready implementations are in [service patterns](references/service-patterns.md).

## Resources

- [Supabase JS Client Reference](https://supabase.com/docs/reference/javascript/initializing)
- [TypeScript Support & Type Generation](https://supabase.com/docs/reference/javascript/typescript-support)
- [Supabase Auth Reference](https://supabase.com/docs/reference/javascript/auth-signup)
- [Realtime Guide](https://supabase.com/docs/guides/realtime)
- [Storage Guide](https://supabase.com/docs/guides/storage)
- [Python Client Reference](https://supabase.com/docs/reference/python/initializing)

## Next Steps

For database schema design, see `supabase-schema-from-requirements`. For auth deep-dive with RLS policies, see `supabase-install-auth`. For realtime architecture patterns, see `supabase-auth-storage-realtime-core`.

---

**Source:** [`jeremylongshore/claude-code-plugins-plus-skills`](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) → `skills/.curated/supabase-sdk-patterns/SKILL.md`

**Also appears in:** `jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/supabase-pack/skills/supabase-sdk-patterns/SKILL.md`

