Claude
Skills
Sign in
Back

supabase-upgrade-migration

Included with Lifetime
$97 forever

Upgrade Supabase SDK and CLI versions with breaking-change detection and automated code migration. Use when upgrading @supabase/supabase-js (v1→v2 or minor bumps), migrating auth/realtime/storage APIs, or updating the Supabase CLI. Trigger with phrases like "upgrade supabase", "supabase breaking changes", "migrate supabase v2", "update supabase SDK".

Backend & APIssaassupabasemigrationupgradesdk

What this skill does

# Supabase Upgrade Migration

## Overview

Upgrade `@supabase/supabase-js` and the Supabase CLI with breaking-change detection, automated code migration, and rollback planning. Covers the v1-to-v2 migration path (auth method renames, `data`/`error` destructuring, realtime API overhaul), minor version bumps, `@supabase/ssr` adoption, and Python SDK upgrades via `pip install --upgrade supabase`.

## Current State

!`npm list @supabase/supabase-js 2>/dev/null | grep supabase || echo 'supabase-js not installed'`
!`supabase --version 2>/dev/null || echo 'CLI not installed'`
!`pip show supabase 2>/dev/null | grep Version || echo 'Python SDK not installed'`

## Prerequisites

- `@supabase/supabase-js` or the Python `supabase` package installed in the project
- Git with a clean working tree (no uncommitted changes)
- Test suite available for post-upgrade verification
- Node.js >= 18 (for supabase-js v2) or Python >= 3.8 (for Python SDK)

## Instructions

### Step 1: Audit Versions, Scan Usage, and Review Breaking Changes

Check every installed Supabase package and find all import sites in the codebase.

```bash
# Check current SDK version
npm list @supabase/supabase-js

# Check CLI version
supabase --version

# Check Python SDK version
pip show supabase | grep Version

# Find all JS/TS Supabase imports
grep -rn "from '@supabase/supabase-js'" --include="*.ts" --include="*.tsx" --include="*.js" src/ lib/ app/ 2>/dev/null
grep -rn "createClient" --include="*.ts" --include="*.tsx" --include="*.js" src/ lib/ app/ 2>/dev/null

# Find all Python Supabase imports
grep -rn "from supabase" --include="*.py" src/ app/ 2>/dev/null
```

**supabase-js v1 → v2 breaking changes:**

| v1 Pattern | v2 Replacement | Notes |
|-----------|---------------|-------|
| `createClient(url, key)` | `createClient(url, key)` | Signature unchanged, but return type differs |
| `supabase.auth.session()` | `supabase.auth.getSession()` | Sync → async, returns `{ data: { session } }` |
| `supabase.auth.user()` | `supabase.auth.getUser()` | Sync → async, returns `{ data: { user } }` |
| `supabase.auth.signIn({ email, password })` | `supabase.auth.signInWithPassword({ email, password })` | Method split by auth type |
| `supabase.auth.signIn({ provider: 'google' })` | `supabase.auth.signInWithOAuth({ provider: 'google' })` | OAuth separated |
| `supabase.auth.signIn({ email })` | `supabase.auth.signInWithOtp({ email })` | Magic link separated |
| `supabase.auth.api.resetPasswordForEmail(e)` | `supabase.auth.resetPasswordForEmail(e)` | `.api` namespace removed |
| `{ data: subscription }` from `onAuthStateChange` | `{ data: { subscription } }` | Extra destructuring level |
| `error.message` string parsing | `error.code` enum (`PGRST116`, etc.) | Reliable error matching |
| `.single()` returns error on 0 rows | `.maybeSingle()` for optional rows | New method for nullable results |
| `supabase.from('t').on('INSERT', cb).subscribe()` | `supabase.channel('c').on('postgres_changes', ...).subscribe()` | Realtime v2 channel API |
| `supabase.storage.from('b').download('path')` | Same, but returns `{ data: Blob, error }` | Consistent error/data tuple |

**Realtime v2 migration detail:**

```typescript
// v1 realtime
supabase
  .from('messages')
  .on('INSERT', (payload) => console.log(payload.new))
  .subscribe()

// v2 realtime — channel-based API
supabase
  .channel('messages-insert')
  .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' },
    (payload) => console.log(payload.new))
  .subscribe()
```

### Step 2: Run the Upgrade and Apply Code Migrations

Create a branch, install new packages, and transform code to match v2 APIs.

```bash
# Create upgrade branch
git checkout -b upgrade-supabase-sdk

# Upgrade JS/TS SDK
npm install @supabase/supabase-js@latest

# Upgrade SSR helper (if used with Next.js/SvelteKit/Nuxt)
npm install @supabase/ssr@latest

# Upgrade CLI
npm install -g supabase@latest

# Upgrade Python SDK
pip install --upgrade supabase

# Regenerate TypeScript types from linked project
npx supabase gen types typescript --linked > lib/database.types.ts

# Generate a database migration if schema drifted
npx supabase db diff --use-migra -f upgrade_check
```

Apply auth code migrations:

```typescript
// BEFORE (v1 auth patterns)
const session = supabase.auth.session()
const user = supabase.auth.user()
const { error } = await supabase.auth.signIn({ email, password })
const { data: subscription } = supabase.auth.onAuthStateChange(callback)

// AFTER (v2 auth patterns)
const { data: { session } } = await supabase.auth.getSession()
const { data: { user } } = await supabase.auth.getUser()
const { error } = await supabase.auth.signInWithPassword({ email, password })
const { data: { subscription } } = supabase.auth.onAuthStateChange(callback)
```

Apply error handling migration:

```typescript
// BEFORE (v1 — string matching)
if (error.message.includes('not found')) { ... }

// AFTER (v2 — structured error codes)
if (error.code === 'PGRST116') { ... }  // "not found" → PGRST116
```

### Step 3: Verify, Test, and Prepare Rollback

```bash
# Type check (catches 90% of migration issues)
npx tsc --noEmit

# Run test suite
npm test

# Python tests
python -m pytest tests/ -v

# Manual smoke test critical auth flows:
# 1. Sign up → confirm email → sign in with password
# 2. OAuth sign in → callback handling
# 3. Password reset → email → reset form
# 4. Session refresh across page navigations
# 5. Realtime subscription connect/disconnect
# 6. Storage upload/download round-trip
```

**Rollback procedure** (if upgrade causes issues):

```text
# Option A: Pin to previous version
npm install @supabase/supabase-js@<previous-version>
pip install supabase==<previous-version>

# Option B: Revert the branch
git stash && git checkout main
```

## Output

- `@supabase/supabase-js` upgraded to latest version with `npm list` confirmation
- All `supabase.auth.signIn()` calls migrated to `signInWithPassword` / `signInWithOAuth` / `signInWithOtp`
- Sync auth methods (`session()`, `user()`) replaced with async `getSession()` / `getUser()`
- Realtime subscriptions migrated from `.on()` to channel-based API
- `data`/`error` destructuring updated where return shapes changed
- TypeScript types regenerated from current schema
- Test suite passing, type checking clean
- Rollback branch or version pin documented

## Error Handling

| Error | Cause | Solution |
|-------|-------|----------|
| `Property 'session' does not exist` | v1 sync `.session()` removed in v2 | Replace with `await supabase.auth.getSession()` |
| `Property 'signIn' does not exist` | `signIn` split into multiple methods in v2 | Use `signInWithPassword`, `signInWithOAuth`, or `signInWithOtp` |
| `supabase.auth.api` is undefined | `.api` namespace removed in v2 | Call methods directly on `supabase.auth.*` |
| `TypeError: supabase.from(...).on is not a function` | Realtime API replaced in v2 | Use `supabase.channel().on('postgres_changes', ...)` |
| Type errors after `gen types` | Database schema changed between versions | Update application code to match new generated types |
| `PGRST116` error on `.single()` | Zero rows returned (v2 throws) | Use `.maybeSingle()` for optional lookups |
| `ERR_REQUIRE_ESM` after upgrade | v2 is ESM-only in some bundlers | Update `tsconfig.json` to `"module": "esnext"` or use dynamic `import()` |
| `AuthSessionMissingError` | `getSession()` called before auth initialized | Wrap in `onAuthStateChange` listener or check `session !== null` |

## Examples

**Full v1 → v2 auth migration (Next.js):**

```typescript
// lib/supabase.ts — client initialization (unchanged API)
import { createClient } from '@supabase/supabase-js'
import type { Database } from './database.types'

export const supabase = createClient<Database>(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
```

```typescript
// app/login/page.tsx — v2 auth flow
export async function login(email: string, passwor

Related in Backend & APIs