Production Security Checklist
Before Going Live
This checklist covers security considerations for production Supabase applications. Go through each section before launch and periodically thereafter.
Database Security
Row Level Security
-
RLS enabled on ALL tables
-- Check: Should return no rows with rls_enabled = false SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public' AND rowsecurity = false; -
Policies exist for every table operation
-- Check policies per table SELECT tablename, policyname, cmd FROM pg_policies WHERE schemaname = 'public' ORDER BY tablename; -
WITH CHECK on INSERT and UPDATE policies
-- Review policies for missing WITH CHECK SELECT policyname, with_check FROM pg_policies WHERE cmd IN ('INSERT', 'UPDATE', 'ALL') AND with_check IS NULL;
Data Constraints
- NOT NULL where required
- CHECK constraints for business rules
- Foreign keys with appropriate ON DELETE actions
- Unique constraints where needed
Sensitive Data
- No plain-text passwords or secrets
- Encryption for PII if required
- Separate tables for public vs. private data
Authentication Security
Configuration
- Email confirmation enabled (if required)
- Password strength requirements configured
- Rate limiting on auth endpoints
- Secure session configuration
OAuth Providers
- Only necessary providers enabled
- Correct redirect URLs configured
- Provider secrets not exposed
Token Security
- Appropriate JWT expiry times
- Refresh tokens configured correctly
- Token storage is secure (not localStorage for high-security apps)
API Key Management
- anon key used in frontend only
- service_role key NEVER in frontend code
# Search for exposed keys grep -r "service_role" ./src/ grep -r "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ./src/ - Keys stored in environment variables
- Different keys for dev/staging/production
- Key rotation plan in place
Storage Security
- Buckets have appropriate public/private settings
- RLS policies on storage.objects
- File type restrictions configured
- File size limits set
- No sensitive files in public buckets
Edge Functions Security
- Input validation on all functions
- Error messages don't leak information
- Secrets stored in environment variables
- CORS configured appropriately
- Rate limiting on sensitive operations
Network & Infrastructure
HTTPS
- All connections use HTTPS
- No mixed content warnings
- HSTS headers configured (if using custom domain)
CORS
- Allowed origins are specific (not
*in production) - Methods and headers appropriately restricted
Firewall Rules
- Database not publicly accessible (if not needed)
- IP allowlisting (if required)
Monitoring & Logging
Audit Trail
- Audit logging enabled for sensitive tables
- Logs stored securely
- Log retention policy defined
Alerting
- Alerts for unusual activity
- Error rate monitoring
- Authentication failure monitoring
Regular Reviews
- Periodic security audits scheduled
- Dependency updates tracked
- Access reviews conducted
Application Security
Input Handling
- All user input validated
- SQL injection prevented (RLS + parameterized queries)
- XSS prevention (sanitize output)
- CSRF protection (if using cookies)
Error Handling
- Generic error messages to users
- Detailed errors logged server-side
- No stack traces in production
Dependencies
- Dependencies regularly updated
- Security advisories monitored
- No unnecessary dependencies
Team Security
Access Control
- Principle of least privilege for team members
- MFA enabled for Supabase dashboard
- Service accounts used for CI/CD
- Regular access reviews
Secrets Management
- No secrets in version control
- .gitignore includes .env files
- Secrets manager for production
- Secret rotation schedule
Compliance Considerations
If applicable to your industry:
- GDPR compliance (data residency, deletion rights)
- HIPAA compliance (healthcare data)
- SOC 2 compliance (security controls)
- PCI DSS (payment data)
- Data retention policies
Incident Response
- Incident response plan documented
- Contact list for security incidents
- Backup and recovery tested
- Key rotation procedure documented
Quick Security Audit Query
Run this to check basic security posture:
-- Tables without RLS
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname = 'public'
AND tablename NOT IN (
SELECT tablename FROM pg_tables WHERE rowsecurity = true
);
-- Tables without any policies
SELECT t.tablename
FROM pg_tables t
LEFT JOIN pg_policies p ON t.tablename = p.tablename
WHERE t.schemaname = 'public'
GROUP BY t.tablename
HAVING COUNT(p.policyname) = 0;
-- Policies without WITH CHECK (potential issues)
SELECT tablename, policyname, cmd
FROM pg_policies
WHERE schemaname = 'public'
AND cmd IN ('INSERT', 'UPDATE')
AND with_check IS NULL;
Additional Learning
To build more advanced secure applications with Supabase, consider these related courses:
- Full-Stack RAG with Next.js, Supabase & Gemini: Learn to build AI-powered applications with proper security practices
- SQL Architecture in the AI Era: Master database design for modern AI applications including vector storage security
Key Takeaways
- Use the checklist: Before every deployment
- Automate checks where possible: CI/CD security gates
- Regular audits: Schedule periodic reviews
- Document decisions: Record why certain choices were made
- Plan for incidents: Hope for the best, prepare for the worst
Module Summary
In this module, you've learned:
- Security fundamentals and the layered defense model
- API key types and when to use each
- Common security mistakes and how to avoid them
- A comprehensive production security checklist
Security is an ongoing practice. This checklist is a starting point—adapt it to your specific needs and update it as you learn more about your application's threat model.
A checklist doesn't make you secure, but it helps ensure you don't miss the obvious. The best security comes from understanding your system deeply and thinking like an attacker.

