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.
Discussion
Sign in to join the discussion.

