.claude/skills/supabase-api/SKILL.md
Supabase JavaScript client API and REST API usage. Use when integrating Supabase, setting up clients, or using REST endpoints directly.
npx skillsauth add adaptationio/skrillz supabase-apiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
JavaScript client and REST API reference.
npm install @supabase/supabase-js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
)
import { createClient } from '@supabase/supabase-js'
import { Database } from './database.types'
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
const supabaseAdmin = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE_KEY,
{
auth: {
autoRefreshToken: false,
persistSession: false
}
}
)
const supabase = createClient(url, key, {
auth: {
persistSession: true,
autoRefreshToken: true,
storage: localStorage,
storageKey: 'supabase-auth'
},
global: {
headers: { 'x-custom-header': 'value' }
},
db: {
schema: 'public'
},
realtime: {
params: {
eventsPerSecond: 10
}
}
})
https://<project-ref>.supabase.co/rest/v1/<table>
const headers = {
'apikey': 'your-anon-key',
'Authorization': 'Bearer your-anon-key',
'Content-Type': 'application/json',
'Prefer': 'return=representation' // Return data after mutation
}
# All rows
curl 'https://xxx.supabase.co/rest/v1/users' \
-H "apikey: $SUPABASE_KEY" \
-H "Authorization: Bearer $SUPABASE_KEY"
# Specific columns
curl 'https://xxx.supabase.co/rest/v1/users?select=id,name,email' \
-H "apikey: $SUPABASE_KEY"
# With filter
curl 'https://xxx.supabase.co/rest/v1/users?status=eq.active' \
-H "apikey: $SUPABASE_KEY"
# With pagination (query params)
curl 'https://xxx.supabase.co/rest/v1/users?limit=10&offset=0' \
-H "apikey: $SUPABASE_KEY"
# With pagination (Range header - alternative)
curl 'https://xxx.supabase.co/rest/v1/users' \
-H "apikey: $SUPABASE_KEY" \
-H "Range: 0-9"
# With ordering
curl 'https://xxx.supabase.co/rest/v1/users?order=created_at.desc' \
-H "apikey: $SUPABASE_KEY"
# Get count with results
curl 'https://xxx.supabase.co/rest/v1/users?select=*' \
-H "apikey: $SUPABASE_KEY" \
-H "Prefer: count=exact"
curl -X POST 'https://xxx.supabase.co/rest/v1/users' \
-H "apikey: $SUPABASE_KEY" \
-H "Authorization: Bearer $SUPABASE_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"name": "John", "email": "[email protected]"}'
curl -X PATCH 'https://xxx.supabase.co/rest/v1/users?id=eq.123' \
-H "apikey: $SUPABASE_KEY" \
-H "Authorization: Bearer $SUPABASE_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"name": "John Doe"}'
curl -X POST 'https://xxx.supabase.co/rest/v1/users' \
-H "apikey: $SUPABASE_KEY" \
-H "Authorization: Bearer $SUPABASE_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation,resolution=merge-duplicates" \
-d '{"id": 123, "name": "John"}'
curl -X DELETE 'https://xxx.supabase.co/rest/v1/users?id=eq.123' \
-H "apikey: $SUPABASE_KEY" \
-H "Authorization: Bearer $SUPABASE_KEY"
| Operator | Example |
|----------|---------|
| eq | ?status=eq.active |
| neq | ?status=neq.deleted |
| gt | ?age=gt.18 |
| gte | ?age=gte.21 |
| lt | ?price=lt.100 |
| lte | ?price=lte.50 |
| like | ?name=like.*John* |
| ilike | ?name=ilike.*john* |
| is | ?deleted_at=is.null |
| in | ?status=in.(active,pending) |
| cs | ?tags=cs.{sports,news} (contains) |
| cd | ?tags=cd.{a,b,c} (contained by) |
| or | ?or=(status.eq.active,status.eq.pending) |
| and | ?and=(status.eq.active,verified.eq.true) |
// Select
const { data, error } = await supabase.from('table').select('*')
// Select with filter
const { data } = await supabase.from('table').select('*').eq('id', 1)
// Insert
const { data } = await supabase.from('table').insert({ col: 'value' }).select()
// Update
const { data } = await supabase.from('table').update({ col: 'new' }).eq('id', 1)
// Upsert
const { data } = await supabase.from('table').upsert({ id: 1, col: 'value' })
// Delete
const { error } = await supabase.from('table').delete().eq('id', 1)
// RPC (function call)
const { data } = await supabase.rpc('function_name', { param: 'value' })
// Sign up
await supabase.auth.signUp({ email, password })
// Sign in
await supabase.auth.signInWithPassword({ email, password })
// Sign out
await supabase.auth.signOut()
// Get user
const { data: { user } } = await supabase.auth.getUser()
// Get session
const { data: { session } } = await supabase.auth.getSession()
// Auth state listener
supabase.auth.onAuthStateChange((event, session) => { })
// Upload
await supabase.storage.from('bucket').upload('path', file)
// Download
const { data } = await supabase.storage.from('bucket').download('path')
// Get public URL
const { data } = supabase.storage.from('bucket').getPublicUrl('path')
// Get signed URL
const { data } = await supabase.storage.from('bucket').createSignedUrl('path', 3600)
// Delete
await supabase.storage.from('bucket').remove(['path'])
// List
const { data } = await supabase.storage.from('bucket').list('folder')
// Subscribe to database changes
const channel = supabase
.channel('changes')
.on('postgres_changes', { event: '*', schema: 'public', table: 'posts' }, callback)
.subscribe()
// Broadcast
channel.send({ type: 'broadcast', event: 'message', payload: data })
// Presence
await channel.track({ user_id: '123' })
const state = channel.presenceState()
// Unsubscribe
await supabase.removeChannel(channel)
const { data, error } = await supabase.functions.invoke('function-name', {
body: { key: 'value' }
})
const { data, error } = await supabase.from('users').select('*')
if (error) {
console.error('Error code:', error.code)
console.error('Error message:', error.message)
console.error('Error details:', error.details)
console.error('Error hint:', error.hint)
return
}
// data is safe to use
console.log(data)
| Code | Description |
|------|-------------|
| PGRST116 | No rows returned (single expected) |
| PGRST301 | Multiple rows returned (single expected) |
| 23505 | Unique constraint violation |
| 23503 | Foreign key violation |
| 42501 | RLS policy violation |
| 42P01 | Table doesn't exist |
supabase gen types typescript --local > database.types.ts
import { Database } from './database.types'
// Table row type
type User = Database['public']['Tables']['users']['Row']
// Insert type
type NewUser = Database['public']['Tables']['users']['Insert']
// Update type
type UpdateUser = Database['public']['Tables']['users']['Update']
// Query result type
import { QueryData } from '@supabase/supabase-js'
const usersQuery = supabase.from('users').select('id, name, posts(title)')
type UsersWithPosts = QueryData<typeof usersQuery>
development
Setup secure web-based terminal access to WSL2 from mobile/tablet via ttyd + ngrok/Cloudflare/Tailscale. One-command install, start, stop, status. Use when you need remote terminal access, web terminal, browser-based shell, or mobile access to WSL2 environment.
development
Complete development workflows where Claude writes the code while Gemini and Codex provide research, planning, reviews, and different perspectives. Claude remains the main developer. Use for complex projects requiring expert planning and multi-perspective reviews.
development
Systematic progress tracking for skill development. Manages task states (pending/in_progress/completed), updates in real-time, reports progress, identifies blockers, and maintains momentum. Use when tracking skill development, coordinating work, or reporting progress.
testing
Comprehensive testing workflow orchestrating functional testing, example validation, integration testing, and usability assessment. Sequential workflow for complete skill testing from examples through scenarios to integration validation. Use when conducting thorough testing, pre-deployment validation, ensuring skill functionality, or comprehensive quality checks.