Deployment
Deploy LaunchSaaS to production on Vercel, Cloudflare, Railway, or Docker. Step-by-step guides with environment setup and best practices.
Deployment
This guide covers deploying LaunchSaaS to production, including platform-specific instructions and best practices.
Pre-Deployment Checklist
Before deploying, ensure you have:
- Database set up and accessible from production
- All required environment variables configured
- Database migrations applied (
pnpm run db:migrate) - Admin user created (
pnpm run init:scripts) - Stripe webhooks configured with production URL
- Email domain verified in Resend
- Social OAuth apps configured with production callback URLs
-
NEXT_PUBLIC_APP_ENVset toproduction -
NEXT_PUBLIC_APP_URLset to your production domain
Vercel (Recommended)
Vercel is the creators of Next.js and offers the best deployment experience.
Deploy via Dashboard
- Go to vercel.com
- Click "Add New Project"
- Import your Git repository
- Configure environment variables (add all from your
.envfile) - Click "Deploy"
Deploy via CLI
- Install Vercel CLI:
pnpm install -g vercel- Login and deploy:
vercel login
vercel --prodEnvironment Variables
Add all required environment variables in Vercel Dashboard:
- Go to Project Settings → Environment Variables
- Add each variable for "Production" environment
- Redeploy after adding variables
Custom Domain
- Go to Project Settings → Domains
- Add your domain
- Configure DNS (CNAME to
cname.vercel-dns.comor use Vercel nameservers) - Wait for DNS propagation
Railway
Railway offers simple deployment with database included.
Deploy to Railway
- Go to railway.app
- Click "New Project"
- Select "Deploy from GitHub repo"
- Select your repository
- Add environment variables
- Click "Deploy"
Database on Railway
Railway can provision a PostgreSQL database:
- Click "New" → "Database" → "PostgreSQL"
- Copy the connection string
- Add as
DATABASE_URLenvironment variable
Docker (VPS/Self-hosted)
Deploy on your own VPS or server using Docker. This method is ideal when you need full control over your infrastructure.
Recommended Setup: Use Docker for the application and a managed database service (Neon/Supabase) for simplicity and reliability.
Prerequisites
- VPS or server with Docker installed
- Managed database (Neon or Supabase recommended)
- Domain name with DNS configured (optional)
- At least 2GB RAM and 10GB disk space
Quick Start
- Clone and configure
git clone https://github.com/your-repo/launchsaas.git
cd launchsaas
cp .env.example .env- Edit
.envfile
Configure the required variables:
DATABASE_URL- Your managed database connection stringBETTER_AUTH_SECRET- Random 32+ character stringADMIN_EMAILandADMIN_PASSWORD- Admin credentialsNEXT_PUBLIC_APP_URL- Your production domain
- Build and start
./docker-quickstart.shYour application is now running at http://localhost:3000
Using Self-hosted Database (Optional)
If you prefer to run PostgreSQL in Docker instead of using a managed service:
- Uncomment database in
docker-compose.yml
# Remove the # from these lines:
postgres:
image: postgres:16-alpine
# ... rest of config
volumes:
postgres_data:- Update
.envwith Docker database URL
DATABASE_URL=postgres://postgres:postgres@postgres:5432/launchsaas- Restart containers
./docker-quickstart.sh down
./docker-quickstart.sh upSelf-hosted databases require regular backups and maintenance. Managed services like Neon or Supabase are recommended for production.
Production Setup
1. Configure Reverse Proxy & HTTPS
Choose one of the following options to add HTTPS support:
Option A: SWAG (Recommended for Docker)
SWAG is an all-in-one solution with automatic SSL certificate management via Let's Encrypt.
# Add to your docker-compose.yml
services:
swag:
image: lscr.io/linuxserver/swag:latest
container_name: swag
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
- URL=yourdomain.com
- VALIDATION=http
- [email protected]
volumes:
- ./swag:/config
ports:
- 443:443
- 80:80
restart: unless-stoppedCreate proxy configuration in ./swag/nginx/proxy-confs/launchsaas.subdomain.conf:
server {
listen 443 ssl http2;
server_name yourdomain.com;
include /config/nginx/ssl.conf;
location / {
include /config/nginx/proxy.conf;
proxy_pass http://launchsaas-app:3000;
}
}Option B: Caddy (Simplest)
Automatic HTTPS with minimal configuration:
# Add to docker-compose.yml
services:
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/dataCreate Caddyfile:
yourdomain.com {
reverse_proxy launchsaas-app:3000
}Option C: Nginx
Manual SSL certificate configuration:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}2. Environment Variables
Option A: Use separate environment files (Recommended)
Create different environment files for each environment:
# Create production environment file
cp .env.example .env.prod
# Edit .env.prod with production values
nano .env.prodConfigure production values:
APP_ENV=productionNEXT_PUBLIC_APP_URL=https://yourdomain.com- Production database URL
- Production API keys for all services
Start with specific environment file:
# Using docker-quickstart.sh
./docker-quickstart.sh start --env .env.prod
./docker-quickstart.sh -e .env.staging
# Using docker compose directly
export ENV_FILE=.env.prod
docker compose up -dOption B: Use single .env file
Update your existing .env with production values:
nano .envThen start normally:
./docker-quickstart.shSee Environment Variables for complete list.
3. Database Initialization
Run migrations and create admin user:
docker compose exec app pnpm run initOr run separately:
docker compose exec app pnpm run db:migrate
docker compose exec app pnpm run init:scriptsAvailable Commands
./docker-quickstart.sh start # Build and start (default)
./docker-quickstart.sh build # Build Docker image only
./docker-quickstart.sh up # Start containers only
./docker-quickstart.sh down # Stop containers
./docker-quickstart.sh restart # Restart containers
./docker-quickstart.sh logs # View logs (Ctrl+C to exit)
./docker-quickstart.sh clean # Remove containers and imagesUsing different environment files:
# Start with production environment
./docker-quickstart.sh start --env .env.prod
# Start with staging environment
./docker-quickstart.sh start -e .env.staging
# Build with specific environment
./docker-quickstart.sh build --env .env.prod
# View logs (no environment file needed)
./docker-quickstart.sh logsCommon workflows:
# Development
./docker-quickstart.sh
# Production
cp .env.example .env.prod
# Edit .env.prod with production values
./docker-quickstart.sh start --env .env.prod
# Switch environments
./docker-quickstart.sh down
./docker-quickstart.sh start --env .env.staging
# View logs and restart
./docker-quickstart.sh logs
./docker-quickstart.sh restartTroubleshooting
Port already in use:
# Change port in .env
APP_PORT=3001Then restart:
./docker-quickstart.sh restartDatabase connection failed:
- Verify
DATABASE_URLis correct - Ensure database allows connections from Docker
- For managed database, check IP whitelist settings
- Test connection:
docker compose exec app node -e "console.log(process.env.DATABASE_URL)"
Container won't start:
# Check error logs
./docker-quickstart.sh logs
# Check container status
docker compose ps
# Rebuild if needed
./docker-quickstart.sh clean
./docker-quickstart.sh buildOut of disk space:
# Clean up Docker resources
docker system prune -a
# Remove old containers and images
./docker-quickstart.sh cleanWhy Vercel/Railway Instead?
While Docker gives you full control, managed platforms offer significant advantages:
- ✅ Automatic SSL certificates
- ✅ Zero-downtime deployments
- ✅ Built-in CDN and edge caching
- ✅ Automatic scaling
- ✅ Free tier for small projects
- ✅ No server maintenance
Use Docker when you need:
- Full server control
- Custom infrastructure requirements
- Existing VPS/server to utilize
- Compliance with specific hosting requirements
- Integration with existing Docker-based infrastructure
Post-Deployment
Update Webhook URLs
After deployment, update your Stripe webhook URL:
- Go to Stripe Dashboard → Webhooks
- Update endpoint URL to:
https://yourdomain.com/api/auth/stripe/webhook
Update OAuth Callback URLs
Update social login callback URLs:
- GitHub:
https://yourdomain.com/api/auth/callback/github - Google:
https://yourdomain.com/api/auth/callback/google
Verify Deployment
- Visit your production URL
- Test sign up and sign in
- Test payment flow with Stripe test cards
- Verify emails are being sent
- Check admin panel access