supabase-prod-checklist
Execute Supabase production deployment checklist and rollback procedures. Use when deploying Supabase integrations to production, preparing for launch, or implementing go-live procedures. Trigger with phrases like "supabase production", "deploy supabase", "supabase go-live", "supabase launch checklist".
Install
mkdir -p .claude/skills/supabase-prod-checklist && curl -L -o skill.zip "https://mcp.directory/api/skills/download/4213" && unzip -o skill.zip -d .claude/skills/supabase-prod-checklist && rm skill.zipInstalls to .claude/skills/supabase-prod-checklist
About this skill
Supabase Production Deployment Checklist
Overview
Actionable 14-step checklist for taking a Supabase project to production. Covers RLS enforcement, key separation, connection pooling (Supavisor), backups/PITR, network restrictions, custom domains, auth emails, rate limits, monitoring, Edge Functions, Storage policies, indexes, and migrations. Based on Supabase's official production guide.
Prerequisites
- Supabase project on Pro plan or higher (required for PITR, network restrictions)
- Separate production project (never share dev/prod)
@supabase/supabase-jsv2+ installed- Supabase CLI installed (
npx supabase --version) - Domain and DNS configured for custom domain
- Deployment platform ready (Vercel, Netlify, Cloudflare, etc.)
Instructions
Step 1: Enforce Row Level Security on ALL Tables
RLS is the single most critical production requirement. Without it, any client with your anon key can read/write every row.
-- Audit: find tables WITHOUT RLS enabled
-- This query MUST return zero rows before going live
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public' AND rowsecurity = false;
-- Enable RLS on a table
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- Create a basic read policy (authenticated users see own rows)
CREATE POLICY "Users can view own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = user_id);
-- Create an insert policy
CREATE POLICY "Users can insert own profile"
ON public.profiles
FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Create an update policy
CREATE POLICY "Users can update own profile"
ON public.profiles
FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
- RLS enabled on every public table (zero rows from audit query above)
- SELECT, INSERT, UPDATE, DELETE policies defined for each table
- Policies tested with both authenticated and anonymous roles
- No tables use
USING (true)without intent (public read tables only)
Step 2: Enforce Key Separation — Anon vs Service Role
The anon key is safe for client-side code. The service_role key bypasses RLS entirely and must never leave server-side environments.
// Client-side — ONLY use anon key
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! // Safe for browsers
);
// Server-side only — service_role key (API routes, webhooks, cron jobs)
import { createClient } from '@supabase/supabase-js';
const supabaseAdmin = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!, // NEVER expose to client
{ auth: { autoRefreshToken: false, persistSession: false } }
);
- Anon key used in all client-side code (
NEXT_PUBLIC_prefix) - Service role key used only in server-side code (API routes, Edge Functions)
- Service role key not in any client bundle (verify with
grep -r "service_role" dist/) - Database password changed from the auto-generated default
Step 3: Configure Connection Pooling (Supavisor)
Supabase uses Supavisor for connection pooling. Serverless functions (Vercel, Netlify, Cloudflare Workers) MUST use the pooled connection string to avoid exhausting the database connection limit.
# Direct connection (migrations, admin tasks only)
postgresql://postgres:[PASSWORD]@db.[REF].supabase.co:5432/postgres
# Pooled connection via Supavisor (application code — USE THIS)
# Port 6543 = Supavisor pooler (vs 5432 direct)
postgresql://postgres.[REF]:[PASSWORD]@aws-0-us-east-1.pooler.supabase.com:6543/postgres
// For serverless environments — use pooled connection
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
{
db: { schema: 'public' },
// Supavisor handles pooling at port 6543
// No need to configure pgBouncer settings in the client
}
);
- Application code uses pooled connection string (port 6543)
- Direct connection reserved for migrations and admin tasks only
- Connection string in deployment platform env vars (not hardcoded)
- Verified pool mode:
transactionfor serverless,sessionfor long-lived connections
Step 4: Enable Database Backups
Supabase provides automatic daily backups on Pro plan. Point-in-time recovery (PITR) enables granular restores.
- Automatic daily backups enabled (Pro plan — verify in Dashboard > Database > Backups)
- Point-in-time recovery configured (Dashboard > Database > Backups > PITR)
- Tested restore procedure on a staging project (do not skip this)
- Migration files committed to version control (
supabase/migrations/directory) -
npx supabase db pushtested against a fresh project to verify migrations replay cleanly
Step 5: Configure Network Restrictions
Restrict database access to known IP addresses. This prevents unauthorized direct database connections even if credentials leak.
- IP allowlist configured (Dashboard > Database > Network Restrictions)
- Only deployment platform IPs and team office IPs are allowed
- Verified that application still connects after restrictions applied
- Documented which IPs are allowed and why
Step 6: Configure Custom Domain
A custom domain replaces the default *.supabase.co URLs with your brand domain for API and auth endpoints.
- Custom domain configured (Dashboard > Settings > Custom Domains)
- DNS CNAME record added and verified
- SSL certificate provisioned and active
- Application code updated to use custom domain URL
- OAuth redirect URLs updated to use custom domain
Step 7: Customize Auth Email Templates
Default Supabase auth emails show generic branding. Customize them so users see your domain and brand.
- Confirmation email template customized (Dashboard > Auth > Email Templates)
- Password reset email template customized
- Magic link email template customized
- Invite email template customized
- Custom SMTP configured (Dashboard > Auth > SMTP Settings) — avoids rate limits and improves deliverability
- Email confirmation enabled (Dashboard > Auth > Settings)
- OAuth redirect URLs restricted to production domains only
- Unused auth providers disabled
Step 8: Understand Rate Limits Per Tier
Supabase enforces rate limits that vary by plan. Hitting these in production causes 429 errors.
| Resource | Free | Pro | Team |
|---|---|---|---|
| API requests | 500/min | 1,000/min | 5,000/min |
| Auth emails | 4/hour | 30/hour | 100/hour |
| Realtime connections | 200 concurrent | 500 concurrent | 2,000 concurrent |
| Edge Function invocations | 500K/month | 2M/month | 5M/month |
| Storage bandwidth | 2GB/month | 250GB/month | Custom |
| Database size | 500MB | 8GB | 50GB |
- Rate limits documented for your plan tier
- Client-side retry logic with exponential backoff for 429 responses
- Auth email rate limits understood (use custom SMTP to increase)
- Realtime connection limits planned for expected concurrent users
Step 9: Review Monitoring Dashboards
Supabase provides built-in monitoring. Review these before launch to establish baselines.
// Health check endpoint — deploy this to your application
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
);
export async function GET() {
const start = Date.now();
const { data, error } = await supabase
.from('_health_check') // Create a small table for this
.select('id')
.limit(1);
const latency = Date.now() - start;
return Response.json({
status: error ? 'unhealthy' : 'healthy',
latency_ms: latency,
timestamp: new Date().toISOString(),
supabase_reachable: !error,
}, { status: error ? 503 : 200 });
}
- Dashboard > Reports reviewed (API requests, auth, storage, realtime)
- Dashboard > Logs > API checked for error patterns
- Dashboard > Database > Performance Advisor reviewed and recommendations applied
- Health check endpoint deployed and monitored (uptime service)
- Error tracking configured (Sentry, LogRocket, etc.)
- Alerts set for: error rate spikes, high latency, connection pool exhaustion
Step 10: Deploy Edge Functions with Proper Env Vars
Edge Functions run on Deno Deploy. Environment variables must be set via the Supabase CLI or Dashboard, not hardcoded.
# Set secrets for Edge Functions
npx supabase secrets set STRIPE_SECRET_KEY=sk_live_...
npx supabase secrets set RESEND_API_KEY=re_...
# List current secrets
npx supabase secrets list
# Deploy all Edge Functions
npx supabase functions deploy
# Deploy a specific function
npx supabase functions deploy process-webhook
// supabase/functions/process-webhook/index.ts
import { createClient } from '@supabase/supabase-js';
Deno.serve(async (req) => {
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! // Available automatically
);
const body = await req.json();
// Process webhook payload...
return new Response(JSON.stringify({ received: true }), {
headers: { 'Content-Type': 'application/json' },
});
});
- All Edge Functions deployed to production (
npx supabase functions deploy) - Environment secrets set via
npx supabase secrets set(not hardcoded) -
SUPABASE_URLandSUPABASE_SERVICE_ROLE_KEYavailable automatically (no need to set) - Edge Functions tested with
npx supabase functions servelocally before deploying - CORS headers configured for Edge Functions that receive browser requests
Step 11: Verify Storage Bucket Policies
Storage buckets need ex
Content truncated.
More by jeremylongshore
View all skills by jeremylongshore →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversConnect Supabase projects to AI with Supabase MCP Server. Standardize LLM communication for secure, efficient developmen
Thirdweb — Read/write across 2,000+ blockchains: query data, analyze/deploy contracts, and execute transactions with a p
Alibaba Cloud Supabase integrates project management, GPDB tools, Edge Functions, storage, and cloud automation for seam
Connect Blender to Claude AI for seamless 3D modeling. Use AI 3D model generator tools for faster, intuitive, interactiv
Terminal control, file system search, and diff-based file editing for Claude and other AI assistants. Execute shell comm
XcodeBuild streamlines iOS app development for Apple developers with tools for building, debugging, and deploying iOS an
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.