This guide covers everything you need to configure your Next.js SaaS Starter for a secure, production-ready deployment.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/nextjs/saas-starter/llms.txt
Use this file to discover all available pages before exploring further.
Production Environment Variables
All five environment variables are required for production. Unlike development, you must not use test or development credentials in production.Complete Configuration
.env
Environment Variable Details
BASE_URL
Purpose: Your production domain, used for redirects and webhooks
Production Value: https://yourdomain.com
Notes:
- Must include protocol (
https://) - No trailing slash
- Must match your actual domain
- Used by authentication redirects and Stripe checkout
POSTGRES_URL
Purpose: Connection string for your production PostgreSQL database
Format: postgresql://[user]:[password]@[host]:[port]/[database]?[params]
Example:
- Always use SSL/TLS in production (
?sslmode=require) - Use connection pooling for serverless environments
- Restrict database user permissions (no DROP, CREATE on production)
- Use strong, unique passwords
STRIPE_SECRET_KEY
Purpose: Authenticates requests to Stripe API
Production Value: sk_live_... (not sk_test_...)
Where to Find:
- Go to dashboard.stripe.com/apikeys
- Toggle Viewing test data to OFF (production mode)
- Copy the Secret key
- Never log or expose this key
- Rotate keys if compromised
- Used in
lib/payments/stripe.tsto initialize Stripe SDK
STRIPE_WEBHOOK_SECRET
Purpose: Verifies webhook requests are from Stripe
Production Value: whsec_...
How to Get: See Stripe Production Webhook Setup below
Security Notes:
- Each webhook endpoint has a unique signing secret
- Used for signature verification in
app/api/stripe/webhook/route.ts:5-20 - Production and test webhooks have different secrets
AUTH_SECRET
Purpose: Secret key for signing and verifying JWT authentication tokens
Production Value: 32+ character random string
Generate Securely:
- Used by
lib/auth/session.tsto sign JWTs - Protects against token forgery
- Critical for authentication security
Stripe Production Webhook Setup
Production webhooks are essential for handling subscription lifecycle events.Step-by-Step Configuration
Navigate to Stripe Dashboard
- Go to dashboard.stripe.com
- Switch to production mode (toggle in top right should be OFF)
- Navigate to Developers → Webhooks
Create Webhook Endpoint
Click Add endpoint and configure:Endpoint URL:
https://yourdomain.com/api/stripe/webhookThis URL must match your production domain. The route is implemented in
app/api/stripe/webhook/route.ts.Select Events
Add the following events that your application listens for:
- ✅
customer.subscription.updated - ✅
customer.subscription.deleted
handleSubscriptionChange() in lib/payments/stripe.ts.Copy Signing Secret
After creating the endpoint:
- Click on your new webhook endpoint
- Click Reveal next to Signing secret
- Copy the secret (starts with
whsec_...) - Add to your environment variables as
STRIPE_WEBHOOK_SECRET
Webhook Implementation
The webhook handler inapp/api/stripe/webhook/route.ts performs:
- Signature Verification (line 14): Validates request is from Stripe
- Event Processing (lines 23-31): Handles subscription updates/deletions
- Database Updates: Calls
handleSubscriptionChange()to update user subscriptions
Monitoring Webhooks
Monitor webhook delivery in Stripe Dashboard:- Go to Developers → Webhooks
- Click on your endpoint
- View Recent deliveries to see success/failure status
{"received": true}
Common Failures:
- 400 Bad Request: Signature verification failed (check
STRIPE_WEBHOOK_SECRET) - 500 Internal Server Error: Application error (check logs)
- Timeout: Request took >5 seconds (optimize webhook handler)
Security Considerations
Production deployments require additional security measures.Authentication Security
The application uses JWT-based authentication with several security features:Session Management
Implementation:middleware.ts:18-41
httpOnly: Cookies inaccessible to JavaScript (XSS protection)secure: Only transmitted over HTTPSsameSite: 'lax': Prevents CSRF attacks- 24-hour expiration with automatic renewal
Route Protection
Global Middleware:middleware.ts:5-14
/dashboard require authentication.
Password Security
Passwords are hashed using bcrypt with automatic salting:- Implemented in authentication actions
- Never store plaintext passwords
- Hash strength is automatically managed by bcrypt
API Security
All API routes should validate authentication:Environment Security
Secrets Management
Secrets Management
Never commit secrets to version control:
- Add
.envto.gitignore - Use platform environment variables (Vercel, AWS, etc.)
- Rotate secrets if exposed
- Use different secrets per environment
HTTPS/SSL
HTTPS/SSL
Always use HTTPS in production:
- Vercel provides automatic SSL certificates
- Enforce HTTPS for all requests
- Check
secure: truein cookie configuration - Use
sslmode=requirefor database connections
Database Security
Database Security
Protect your production database:
- Use strong passwords (20+ random characters)
- Enable SSL/TLS for connections
- Restrict IP access if possible
- Use least-privilege database users
- Regular backups and disaster recovery plan
- Monitor for suspicious queries
Dependency Security
Dependency Security
Keep dependencies updated:Set up automated security alerts:
- Enable Dependabot on GitHub
- Monitor npm advisories
- Test updates before deploying
Database Considerations
Production database setup requires careful planning.Connection Pooling
Why Needed: Serverless functions create new connections per request Solutions:- Vercel Postgres: Built-in connection pooling
- Neon: Serverless-native with automatic pooling
- Supabase: Use connection pooling port (6543)
- PgBouncer: Self-hosted connection pooler
Migrations
Run migrations using Drizzle Kit:Database Schema
The application schema is defined inlib/db/schema.ts with tables for:
users- User accounts and authenticationteams- Team/workspace managementteamMembers- User-team relationships with RBACactivityLogs- Audit trail of user actions
Backups
Automated Backups:- Vercel Postgres: Automatic daily backups (retained 7 days)
- Neon: Point-in-time recovery (configurable retention)
- Supabase: Daily backups (configurable retention)
Monitoring
Monitor database health:- Connection count: Ensure not hitting limits
- Query performance: Identify slow queries
- Storage usage: Plan for scaling
- Error rates: Catch issues early
Production Checklist
Before going live, verify all items:Environment Variables
Environment Variables
- ✅
BASE_URLset to production domain - ✅
POSTGRES_URLpoints to production database with SSL - ✅
STRIPE_SECRET_KEYis production key (sk_live_...) - ✅
STRIPE_WEBHOOK_SECRETfrom production webhook - ✅
AUTH_SECRETis cryptographically random - ✅ No test or development values in production
Stripe Configuration
Stripe Configuration
- ✅ Using production API keys
- ✅ Production webhook created
- ✅ Webhook events configured (subscription.updated, subscription.deleted)
- ✅ Webhook secret added to environment variables
- ✅ Test webhook receives 200 OK response
- ✅ Webhook URL matches production domain
Database
Database
- ✅ Production database created
- ✅ Migrations applied
- ✅ SSL/TLS enabled
- ✅ Connection pooling configured
- ✅ Automated backups enabled
- ✅ Database credentials are secure
Security
Security
- ✅ HTTPS enabled (automatic with Vercel)
- ✅ Secure cookie settings verified
- ✅ Authentication middleware active
- ✅ No secrets in source control
- ✅ Dependencies updated and audited
- ✅ Error handling doesn’t expose sensitive info
Testing
Testing
- ✅ Production build succeeds (
pnpm build) - ✅ Authentication flow works
- ✅ Stripe checkout completes successfully
- ✅ Webhooks process correctly
- ✅ Protected routes require authentication
- ✅ Database operations work correctly
Going Live
Once all checklist items are complete:Final Testing
Test critical user flows:
- Sign up new account
- Complete payment (use real card, then refund)
- Access dashboard
- Manage subscription via customer portal
Monitor Initial Traffic
Watch logs and metrics closely:
- Check for errors in deployment logs
- Monitor webhook delivery success rate
- Verify database connections are stable
- Watch for authentication issues
Consider a soft launch with limited users before full public release to catch any production-specific issues.
Support and Maintenance
Regular Maintenance
- Weekly: Review error logs and webhook delivery
- Monthly: Update dependencies, review security advisories
- Quarterly: Database performance review, backup restoration test
Getting Help
- GitHub Issues: github.com/nextjs/saas-starter/issues
- Next.js Docs: nextjs.org/docs
- Stripe Support: support.stripe.com
- Vercel Support: vercel.com/support
Deploy to Vercel
Ready to deploy? Follow our step-by-step Vercel deployment guide