Claude-code-plugins-plus supabase-upgrade-migration
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/supabase-pack/skills/supabase-upgrade-migration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-supabase-upgrade-migration && rm -rf "$T"
manifest:
plugins/saas-packs/supabase-pack/skills/supabase-upgrade-migration/SKILL.mdsource content
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
or the Python@supabase/supabase-js
package installed in the projectsupabase- 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.
# 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 |
|---|---|---|
| | Signature unchanged, but return type differs |
| | Sync → async, returns |
| | Sync → async, returns |
| | Method split by auth type |
| | OAuth separated |
| | Magic link separated |
| | namespace removed |
from | | Extra destructuring level |
string parsing | enum (, etc.) | Reliable error matching |
returns error on 0 rows | for optional rows | New method for nullable results |
| | Realtime v2 channel API |
| Same, but returns | Consistent error/data tuple |
Realtime v2 migration detail:
// 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.
# 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:
// 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:
// 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
# 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):
# 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
upgraded to latest version with@supabase/supabase-js
confirmationnpm list- All
calls migrated tosupabase.auth.signIn()
/signInWithPassword
/signInWithOAuthsignInWithOtp - Sync auth methods (
,session()
) replaced with asyncuser()
/getSession()getUser() - Realtime subscriptions migrated from
to channel-based API.on()
/data
destructuring updated where return shapes changederror- TypeScript types regenerated from current schema
- Test suite passing, type checking clean
- Rollback branch or version pin documented
Error Handling
| Error | Cause | Solution |
|---|---|---|
| v1 sync removed in v2 | Replace with |
| split into multiple methods in v2 | Use , , or |
is undefined | namespace removed in v2 | Call methods directly on |
| Realtime API replaced in v2 | Use |
Type errors after | Database schema changed between versions | Update application code to match new generated types |
error on | Zero rows returned (v2 throws) | Use for optional lookups |
after upgrade | v2 is ESM-only in some bundlers | Update to or use dynamic |
| called before auth initialized | Wrap in listener or check |
Examples
Full v1 → v2 auth migration (Next.js):
// 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! )
// app/login/page.tsx — v2 auth flow export async function login(email: string, password: string) { const { data, error } = await supabase.auth.signInWithPassword({ email, password, }) if (error) { // v2: use error.code instead of parsing error.message if (error.code === 'invalid_credentials') { return { success: false, message: 'Invalid email or password' } } throw error } return { success: true, session: data.session } }
// hooks/useAuth.ts — v2 session listener import { useEffect, useState } from 'react' import { supabase } from '@/lib/supabase' import type { Session } from '@supabase/supabase-js' export function useAuth() { const [session, setSession] = useState<Session | null>(null) useEffect(() => { // v2: getSession is async, returns nested { data: { session } } supabase.auth.getSession().then(({ data: { session } }) => { setSession(session) }) // v2: subscription nested one level deeper const { data: { subscription } } = supabase.auth.onAuthStateChange( (_event, session) => setSession(session) ) return () => subscription.unsubscribe() }, []) return session }
Python SDK upgrade:
# Before (supabase-py < 2.0) from supabase import create_client supabase = create_client(url, key) data = supabase.table("users").select("*").execute() users = data["data"] # After (supabase-py >= 2.0) from supabase import create_client, Client supabase: Client = create_client(url, key) response = supabase.table("users").select("*").execute() users = response.data # attribute access, not dict
Resources
- supabase-js v2 Migration Guide — official step-by-step
- supabase-js Releases — changelog for every version
- Supabase CLI Releases — CLI changelog
- Auth Helpers Migration —
→@supabase/auth-helpers@supabase/ssr - Realtime v2 Guide — channel-based API reference
- supabase-py Releases — Python SDK changelog
Next Steps
For CI integration with the upgraded SDK, see
supabase-ci-integration. For database migration workflows after schema changes, see supabase-migration-deep-dive.