Install
$ agentstack add skill-iwritec0de-app-dev-supabase ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Supabase Skill
You are a Supabase expert for Next.js applications using the App Router.
Critical Rules
- Always enable RLS on every table — a table without Row Level Security is open to any authenticated user by default
- Use the server-side client for Server Components —
createServerClientfrom@supabase/ssrreads cookies via Next.jscookies(); it never leaks tokens to the browser - Use the browser client for Client Components —
createBrowserClientmanages the session in the browser; it must never be used in Server Components or Route Handlers - Never expose the
service_rolekey on the client — it bypasses RLS entirely; keep it server-only in environment variables prefixedSUPABASE_SERVICE_ROLE_KEY(neverNEXT_PUBLIC_) - Use database migrations for schema changes — never edit schema through the Supabase dashboard in production; use
supabase migration newand commit SQL files to version control - Always use parameterized queries — the Supabase client does this automatically; never interpolate user input into raw SQL strings
- Refresh sessions in middleware — call
supabase.auth.getUser()inmiddleware.tson every request to keep the session cookie fresh
Client Setup
Install the required packages:
npm install @supabase/supabase-js @supabase/ssr
Server Component / Route Handler client — reads and writes cookies via Next.js cookies():
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
import type { Database } from '@/types/supabase'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {} // Safe to ignore in Server Components; middleware handles refresh
},
},
}
)
}
Client Component client — manages the session in the browser:
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
import type { Database } from '@/types/supabase'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Read reference/auth-patterns.md for the full middleware setup, sign-in/sign-up flows, OAuth, and protected route patterns.
Database
Always import your generated types for full type safety:
import type { Database } from '@/types/supabase'
// Generate: npx supabase gen types typescript --local > types/supabase.ts
Common query patterns:
const supabase = await createClient()
// Select with filter
const { data, error } = await supabase
.from('posts')
.select('id, title, created_at')
.eq('user_id', userId)
.order('created_at', { ascending: false })
// Insert
const { data, error } = await supabase
.from('posts')
.insert({ title, body, user_id: userId })
.select()
.single()
// Upsert
const { error } = await supabase
.from('profiles')
.upsert({ id: userId, display_name: name })
Read reference/database-patterns.md for RLS policy patterns, migrations, RPC functions, joins, and views.
RLS Policies — Quick Reference
-- Authenticated users can read all rows
CREATE POLICY "authenticated read" ON posts
FOR SELECT TO authenticated USING (true);
-- Users can only modify their own rows
CREATE POLICY "owner write" ON posts
FOR ALL TO authenticated USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- Role-based access using JWT claims
CREATE POLICY "admin only" ON admin_logs
FOR SELECT TO authenticated
USING (auth.jwt() ->> 'role' = 'admin');
Read reference/database-patterns.md for full RLS patterns including multi-tenancy, team-based access, and helper functions.
Storage
// Upload a file
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${userId}/avatar.png`, file, { upsert: true })
// Get a public URL (public bucket)
const { data: { publicUrl } } = supabase.storage
.from('avatars')
.getPublicUrl(`${userId}/avatar.png`)
// Get a signed URL (private bucket, expires in 60 seconds)
const { data, error } = await supabase.storage
.from('documents')
.createSignedUrl(`${userId}/file.pdf`, 60)
Read reference/realtime-storage.md for image transformations, resumable uploads, and storage RLS.
Realtime
'use client'
// Subscribe to table changes
const channel = supabase
.channel('posts-changes')
.on('postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'posts' },
(payload) => setItems(prev => [payload.new as Post, ...prev])
)
.subscribe()
return () => { supabase.removeChannel(channel) }
Read reference/realtime-storage.md for presence, broadcast, and channel cleanup patterns.
Anti-Patterns
- Do not disable RLS — even temporarily; attackers do not wait for you to re-enable it
- Do not use
service_roleon the client — it bypasses all security policies; it belongs only in trusted server environments - Do not skip migrations — dashboard edits to schema are not tracked in version control and will diverge between environments
- Do not store auth state in localStorage — the
@supabase/ssrclient handles sessions via HttpOnly cookies; localStorage is not accessible server-side and is vulnerable to XSS - Do not call
getSession()on the server — usegetUser()instead;getSession()does not revalidate the token against the Supabase server - Do not use
createClientfrom@supabase/supabase-jsin Next.js App Router — use@supabase/ssr; the base client does not integrate with Next.js cookie handling
Related
reference/auth-patterns.md— Sign up, sign in, OAuth, magic link, middleware, protected routes, RBACreference/database-patterns.md— Schema design, RLS policies, migrations, RPC functions, joins, viewsreference/realtime-storage.md— Realtime subscriptions, presence, broadcast, storage upload/download, signed URLs- Supabase docs: https://supabase.com/docs
@supabase/ssrdocs: https://supabase.com/docs/guides/auth/server-side/nextjs
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: iwritec0de
- Source: iwritec0de/app-dev
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.