Saturday, April 12th 2025 · 5 min read
Deploying Your Next.js SaaS to Production: Complete Guide
A comprehensive guide to deploying Next.js SaaS applications to production. Covers Vercel, Railway, AWS, database setup, environment variables, monitoring, and production checklist.
You've built your SaaS application. Now it's time to deploy it to production where real users can access it. This guide covers everything from choosing a hosting provider to monitoring your live application.
Choosing a Hosting Provider
Vercel: The Default Choice
Vercel created Next.js and offers the most optimized deployment experience:
Pros:
- Zero-config deployment
- Edge network with 40+ regions
- Automatic preview deployments
- Built-in analytics and monitoring
- Best-in-class caching
Cons:
- Can get expensive at scale
- Some advanced features require Pro plan
- Vendor lock-in for some features
Best for: Most SaaS applications, especially those starting out.
Railway: Simple and Affordable
Railway offers a straightforward deployment experience with predictable pricing:
Pros:
- Simple pricing ($5/month + usage)
- Great developer experience
- Built-in PostgreSQL and Redis
- No cold starts
Cons:
- Smaller edge network than Vercel
- Fewer built-in analytics tools
- Less documentation
Best for: Cost-conscious teams, applications with high compute needs.
AWS (Amplify or ECS)
AWS offers the most control and scalability:
Pros:
- Maximum control and customization
- Enterprise-grade security
- Global infrastructure
- Cost-effective at scale
Cons:
- Steep learning curve
- Complex configuration
- More operational overhead
Best for: Enterprise applications, teams with DevOps expertise.
Comparison Table
| Feature | Vercel | Railway | AWS Amplify |
|---|---|---|---|
| Setup Time | 5 min | 10 min | 30+ min |
| Minimum Cost | $0 | $5/mo | $0 |
| Auto Scaling | Yes | Yes | Yes |
| Edge Functions | Yes | No | Yes |
| Database | Separate | Built-in | Separate |
| Custom Domains | Yes | Yes | Yes |
Pre-Deployment Checklist
Before deploying, ensure you've completed these steps:
1. Environment Variables
Create a .env.production template and verify all variables:
# Database
DATABASE_URL=postgresql://...
# Authentication
AUTH_SECRET=min-32-characters
AUTH_URL=https://yourdomain.com
# Stripe
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
# Email
RESEND_API_KEY=re_...
# Monitoring
SENTRY_DSN=https://...2. Build Verification
Test your production build locally:
# Build the application
pnpm build
# Start in production mode
pnpm start
# Verify all pages load correctly
# Test authentication flow
# Test Stripe checkout3. Database Migration
Ensure migrations are ready:
# Generate migration from schema changes
pnpm prisma migrate dev
# Deploy migrations to production
pnpm prisma migrate deployDeploying to Vercel
Step 1: Connect Repository
- Go to vercel.com and sign in
- Click "Add New Project"
- Import your GitHub repository
- Vercel auto-detects Next.js settings
Step 2: Configure Environment Variables
Add your production environment variables:
# In Vercel Dashboard → Settings → Environment Variables
DATABASE_URL=postgresql://...
AUTH_SECRET=your-production-secret
STRIPE_SECRET_KEY=sk_live_...Step 3: Configure Build Settings
For most Next.js apps, defaults work. For monorepos:
// vercel.json
{
"buildCommand": "pnpm build",
"outputDirectory": ".next",
"installCommand": "pnpm install"
}Step 4: Deploy
Push to your main branch to trigger deployment:
git push origin mainStep 5: Configure Domain
- Go to Project Settings → Domains
- Add your custom domain
- Update DNS records as instructed
- Wait for SSL certificate provisioning
Deploying to Railway
Step 1: Create Project
# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Create new project
railway initStep 2: Add Services
# Add PostgreSQL
railway add postgresql
# Link to your project
railway linkStep 3: Configure Environment
# Set environment variables
railway variables set DATABASE_URL=${{Postgres.DATABASE_URL}}
railway variables set AUTH_SECRET=your-secret
railway variables set STRIPE_SECRET_KEY=sk_live_...Step 4: Deploy
# Deploy current directory
railway upStep 5: Add Custom Domain
- Go to Railway Dashboard → Settings → Domains
- Add your domain
- Configure DNS CNAME record
Database Setup
Using Neon (Serverless Postgres)
Neon offers serverless PostgreSQL optimized for Next.js:
# 1. Create database at neon.tech
# 2. Get connection string
# 3. Add to environment variables
DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=requireConfigure connection pooling:
// lib/db.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const db =
globalForPrisma.prisma ??
new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error']
});
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = db;
}Using Supabase
Supabase provides PostgreSQL with additional features:
# Connection for Prisma
DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres
# Connection pooling (recommended)
DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:6543/postgres?pgbouncer=trueSetting Up CI/CD
GitHub Actions Pipeline
Create a comprehensive CI/CD pipeline:
# .github/workflows/ci.yml
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm lint
- run: pnpm typecheck
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm test
build:
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm buildMonitoring and Observability
Setting Up Sentry
Add error tracking with Sentry:
pnpm add @sentry/nextjs
npx @sentry/wizard@latest -i nextjsConfigure Sentry:
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
integrations: [
Sentry.replayIntegration({
maskAllText: true,
blockAllMedia: true
})
]
});Setting Up Logging
Use structured logging with Pino:
// lib/logger.ts
import pino from 'pino';
export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
transport:
process.env.NODE_ENV === 'development'
? { target: 'pino-pretty' }
: undefined,
redact: ['password', 'token', 'authorization']
});
// Usage
logger.info({ userId, action: 'login' }, 'User logged in');
logger.error({ error, userId }, 'Payment failed');Uptime Monitoring
Set up uptime monitoring with services like:
- Better Uptime: Great free tier, incident management
- Checkly: Synthetic monitoring, API checks
- Vercel Analytics: Built-in if using Vercel
Production Checklist
Security
- HTTPS enforced on all routes
- Security headers configured (CSP, HSTS, etc.)
- API rate limiting enabled
- Sensitive data encrypted
- Environment variables secured
- Database connections use SSL
Performance
- Images optimized (WebP, proper sizing)
- Fonts preloaded
- Critical CSS inlined
- Bundle size analyzed
- Caching headers configured
- Edge functions for latency-sensitive routes
Reliability
- Error tracking configured (Sentry)
- Logging set up
- Database backups automated
- Uptime monitoring active
- Alerting configured
- Rollback strategy defined
Compliance
- Privacy policy in place
- Terms of service published
- Cookie consent implemented
- Data retention policy defined
- GDPR/CCPA compliance if applicable
Post-Deployment
Monitor First 24 Hours
Watch for:
- Error rates in Sentry
- Performance metrics in hosting dashboard
- Database connection issues
- Failed authentication attempts
- Stripe webhook failures
Set Up Alerts
Configure alerts for:
- Error rate spikes
- Response time degradation
- Database connection failures
- Payment failures
- SSL certificate expiry
Document Runbooks
Create runbooks for common incidents:
## High Error Rate
1. Check Sentry for error details
2. Review recent deployments
3. Check database connectivity
4. Verify third-party API status
5. Rollback if necessary: `vercel rollback`
## Database Connection Issues
1. Check connection pool usage
2. Verify DATABASE_URL is correct
3. Check database provider status
4. Scale connection pool if neededScaling Considerations
As your SaaS grows, consider:
Database
- Add read replicas for read-heavy workloads
- Implement connection pooling (PgBouncer)
- Consider caching layer (Redis)
Compute
- Enable auto-scaling
- Use edge functions for global latency
- Consider dedicated instances for predictable workloads
CDN
- Cache static assets aggressively
- Use image CDN for user-uploaded content
- Implement stale-while-revalidate patterns
Conclusion
Deploying a Next.js SaaS to production involves:
- Choosing the right platform based on your needs
- Proper configuration of environment and build settings
- Database setup with connection pooling
- CI/CD pipelines for reliable deployments
- Monitoring for visibility into production
- Ongoing maintenance and scaling
Start with Vercel or Railway for simplicity, and migrate to more complex setups as your needs grow. The most important thing is shipping—you can always optimize later.
Building a SaaS? Achromatic comes with deployment guides for Vercel, Railway, and Docker, plus built-in Sentry integration and production-ready configurations.
Related Articles
How to Implement Metered Billing with Stripe in Next.js
Learn how to implement usage-based metered billing with Stripe in your Next.js SaaS. Covers metered subscriptions, usage reporting, and real-time tracking.
New Achromatic Starter Kits Are Here
Next.js 16, React 19, Better Auth, tRPC with Prisma or Drizzle ORM. Ship your SaaS faster than ever.
React DoS & Source Code Exposure - Starter Kits Updated
Two new React Server Components vulnerabilities discovered. All Achromatic starter kits updated to patched versions.