Deployment Guide
This guide walks you through deploying your OpenSaas Stack application to production using Vercel and Neon PostgreSQL.
Prerequisites
Before deploying, make sure you have:
- A Vercel account (free tier works)
- A Neon account (free tier includes 10GB storage)
- Your OpenSaas Stack application working locally
- Git repository (GitHub, GitLab, or Bitbucket)
Overview
The deployment process involves:
- Setting up a production database (Neon PostgreSQL)
- Configuring environment variables
- Deploying to Vercel
- Running database migrations
- Verifying your deployment
Total time: ~10-15 minutes for first deployment
Step 1: Create Production Database
Using Neon PostgreSQL
Neon provides serverless PostgreSQL with automatic scaling and a generous free tier.
Sign in to Neon Console
- Go to console.neon.tech
- Create an account or sign in
Create a New Project
- Click "New Project"
- Choose a name (e.g.,
my-app-production) - Select a region close to your users
- Choose Postgres version (16 recommended)
- Click "Create Project"
Get Connection String
- After creation, you'll see your connection string
- It looks like:
postgresql://username:password@ep-xxx.region.aws.neon.tech/dbname?sslmode=require - Important: Copy this string immediately - you'll need it for environment variables
- Neon provides different connection strings:
- Pooled connection (recommended for serverless): Use this for Vercel
- Direct connection: Use this for migrations and Prisma Studio
Enable Connection Pooling (Recommended)
- In your Neon project dashboard, go to "Settings" → "Connection Pooling"
- Enable pooling (it's on by default)
- Use the pooled connection string for your application
- Use the direct connection string for migrations
Step 2: Configure Environment Variables
Local Production Testing (Optional)
Create a .env.production.local file in your project root:
# .env.production.local
DATABASE_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/dbname?sslmode=require&pgbouncer=true"
DIRECT_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
Why two URLs?
DATABASE_URL: Pooled connection for your app (faster, scales better)DIRECT_URL: Direct connection for migrations (Prisma requires this for schema changes)
Update Prisma Schema (If Using Connection Pooling)
Note: Your Prisma schema is auto-generated by opensaas generate, so update your opensaas.config.ts instead:
export default config({
db: {
provider: 'postgresql',
url: process.env.DATABASE_URL!,
directUrl: process.env.DIRECT_URL, // Add this line
},
lists: {
// ... your lists
},
})
Then regenerate:
pnpm generate
Environment Variables for Better Auth (If Using)
If you're using @opensaas/stack-auth, you'll need additional variables:
# .env.production.local
DATABASE_URL="postgresql://..."
DIRECT_URL="postgresql://..."
# Better Auth Configuration
BETTER_AUTH_SECRET="your-random-secret-here"
BETTER_AUTH_URL="https://your-app.vercel.app"
# OAuth Providers (if using)
GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"
Generate a secure secret:
openssl rand -base64 32
Step 3: Deploy to Vercel
You have two options: Vercel CLI (faster) or Vercel Dashboard (more visual).
Option A: Deploy with Vercel CLI (Recommended)
- Install Vercel CLI
npm install -g vercel
- Login to Vercel
vercel login
- Deploy from Project Root
vercel
Follow the prompts:
- "Set up and deploy?" → Yes
- "Which scope?" → Choose your account/team
- "Link to existing project?" → No (first time) or Yes (subsequent deploys)
- "What's your project's name?" → Enter name or press Enter
- "In which directory is your code located?" → Press Enter (current directory)
- "Want to override settings?" → No
- Add Environment Variables
vercel env add DATABASE_URL production
# Paste your pooled connection string
vercel env add DIRECT_URL production
# Paste your direct connection string
# If using Better Auth:
vercel env add BETTER_AUTH_SECRET production
vercel env add BETTER_AUTH_URL production
- Deploy to Production
vercel --prod
Option B: Deploy with Vercel Dashboard
- Push to Git
git add .
git commit -m "Initial deployment"
git push origin main
Import Project in Vercel
- Go to vercel.com/new
- Click "Import Project"
- Select your Git repository
- Click "Import"
Configure Project
- Framework Preset: Next.js (should auto-detect)
- Root Directory:
./(leave default) - Build Command:
pnpm build(or leave default) - Output Directory:
.next(leave default) - Install Command:
pnpm install(or leave default)
Add Environment Variables
- Click "Environment Variables"
- Add each variable:
DATABASE_URL→ Your pooled connection stringDIRECT_URL→ Your direct connection stringBETTER_AUTH_SECRET→ Your random secret (if using auth)BETTER_AUTH_URL→https://your-app.vercel.app(update after first deploy)- Add any OAuth credentials if using social login
Deploy
- Click "Deploy"
- Wait for build to complete (~2-3 minutes)
- Your app will be live at
https://your-app.vercel.app
Step 4: Initialize Production Database
After your first deployment, you need to set up the database schema.
Using Prisma Migrate (Recommended for Production)
If this is your first production deployment:
# Generate migration from your schema
npx prisma migrate dev --name init
# Push migration to production
npx prisma migrate deploy
Set the DIRECT_URL environment variable locally before running migrations:
export DIRECT_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
npx prisma migrate deploy
Using Prisma DB Push (Quick Method)
For rapid iteration (not recommended for production with existing data):
export DIRECT_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
npx prisma db push
Warning: db push can cause data loss. Use migrations for production.
Verify Database Setup
Check your database with Prisma Studio:
export DATABASE_URL="postgresql://user:pass@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
npx prisma studio
Open http://localhost:5555 to view your production database.
Step 5: Verify Deployment
Visit Your App
- Go to your Vercel deployment URL
- You should see your app running
Test Database Connectivity
- If you have an admin UI, try creating a record
- Verify it appears in Prisma Studio
- Check for any console errors
Check Vercel Logs
- Go to your project in Vercel Dashboard
- Click "Deployments" → Select latest deployment → "Functions"
- View logs for any errors
Update Better Auth URL (If Using)
- Go to Vercel Dashboard → Your Project → Settings → Environment Variables
- Update
BETTER_AUTH_URLto your production URL (e.g.,https://your-app.vercel.app) - Redeploy:
vercel --prodor push to Git
Continuous Deployment
Automatic Deployments
Once connected to Git, Vercel automatically deploys:
- Production: Pushes to
mainbranch →your-app.vercel.app - Preview: Pull requests →
your-app-git-branch.vercel.app
Deploy Workflow
# Make changes locally
pnpm dev
# Generate updated schema if config changed
pnpm generate
# Test locally
# ...
# Commit and push
git add .
git commit -m "Add new feature"
git push
# Vercel automatically deploys to preview URL
# Merge PR to deploy to production
Database Migrations in CI/CD
For schema changes, run migrations before deployment:
- Add Migration Step to Vercel
- In
package.json, update build script:
- In
{
"scripts": {
"build": "prisma generate && prisma migrate deploy && next build"
}
}
- Ensure DIRECT_URL is Set
- Add
DIRECT_URLto Vercel environment variables - This allows migrations during build
- Add
Alternative: Run migrations manually before deploying:
# Locally, run migration against production DB
export DIRECT_URL="postgresql://..."
npx prisma migrate deploy
# Then deploy
vercel --prod
Production Considerations
Database Connection Pooling
Serverless functions (like Vercel) create many database connections. Use connection pooling to avoid exhausting your database limits.
Neon provides built-in pooling:
- Use the pooled connection string for
DATABASE_URL - No additional configuration needed
Alternative: Prisma Data Proxy
- Prisma Accelerate provides connection pooling
- Good for multi-region deployments
Environment Variables Management
Never commit secrets to Git:
- Add
.env*.localto.gitignore(already done) - Use Vercel's environment variable UI
- For team projects, use 1Password, AWS Secrets Manager, or similar
Environment-specific variables:
- Development:
.env.local - Production: Vercel Dashboard or
vercel env - Preview: Can inherit from Production or set separately
Database Backups
Neon provides automatic backups:
- Point-in-time recovery (PITR) available on paid plans
- Free tier: Daily snapshots retained for 7 days
Manual backups:
# Export database to SQL file
pg_dump "postgresql://..." > backup.sql
# Restore from backup
psql "postgresql://..." < backup.sql
Monitoring & Logging
Vercel provides:
- Real-time function logs
- Web Analytics (free)
- Speed Insights
Database monitoring:
- Neon Console shows connection count, storage, CPU usage
- Set up alerts for connection limits
Application monitoring:
Performance Optimization
Prisma optimizations:
// In your opensaas.config.ts
export default config({
db: {
provider: 'postgresql',
url: process.env.DATABASE_URL!,
directUrl: process.env.DIRECT_URL,
// Add Prisma preview features
previewFeatures: ['jsonProtocol'], // Faster queries
},
// ...
})
Caching:
- Use Vercel KV for caching
- Cache expensive queries with
next/cache
Security Checklist
Before going live:
- [ ] All secrets are in environment variables (not hardcoded)
- [ ]
BETTER_AUTH_SECRETis cryptographically random - [ ] Database connection uses SSL (
sslmode=require) - [ ] Access control rules are tested and working
- [ ] CORS is configured if using external APIs
- [ ] Rate limiting is configured (consider Vercel's built-in protection)
- [ ] Better Auth session duration is appropriate for your app
- [ ] OAuth redirect URLs are whitelisted in provider settings
Troubleshooting
"Can't reach database server"
Symptoms: Prisma can't connect to Neon database
Solutions:
- Verify
DATABASE_URLis correct (copy from Neon Console) - Check
sslmode=requireis in connection string - Ensure Neon project is not paused (happens on free tier after inactivity)
- Test connection locally:
npx prisma db pull
"Too many connections"
Symptoms: Database refuses new connections
Solutions:
- Use pooled connection string for
DATABASE_URL - Add
connection_limit=10to connection string:typescriptpostgresql://...?sslmode=require&connection_limit=10 - Upgrade Neon plan for more connections
- Use Prisma Accelerate for connection pooling
"Migration failed"
Symptoms: prisma migrate deploy errors
Solutions:
- Ensure you're using
DIRECT_URL(not pooled connection) - Check migration files in
prisma/migrations/are correct - Run
npx prisma migrate resolveto mark failed migrations - For destructive changes, backup data first
"Authentication not working"
Symptoms: Better Auth login fails in production
Solutions:
- Verify
BETTER_AUTH_URLmatches your production domain - Check
BETTER_AUTH_SECRETis set in Vercel - Ensure OAuth redirect URLs are updated in provider settings:
- GitHub:
https://your-app.vercel.app/api/auth/callback/github - Google:
https://your-app.vercel.app/api/auth/callback/google
- GitHub:
- Check browser console for CORS errors
"Build failed"
Symptoms: Vercel deployment fails during build
Solutions:
- Check Vercel build logs for specific error
- Ensure
pnpm generateruns successfully locally - Verify all dependencies are in
package.json(not just devDependencies) - Check Node.js version matches Vercel (use
.nvmrcorpackage.jsonengines field)
"Function execution timeout"
Symptoms: 504 errors on some requests
Solutions:
- Optimize slow database queries (add indexes)
- Use
Promise.all()for parallel operations - Consider background jobs for long-running tasks
- Upgrade Vercel plan for longer timeout (Pro: 60s, Hobby: 10s)
Getting Help
If you're stuck:
- Check OpenSaas Stack GitHub Issues
- Search Vercel Docs
- Check Neon Docs
- Ask in Discord/Community (if available)
Advanced Topics
Custom Domains
Add Domain in Vercel
- Go to Project Settings → Domains
- Add your custom domain (e.g.,
app.example.com) - Follow DNS configuration instructions
Update Better Auth URL
- Update
BETTER_AUTH_URLenvironment variable - Update OAuth redirect URLs in provider settings
- Update
Multi-Environment Setup
For staging + production:
# Create staging database in Neon
# Add to Vercel as staging environment variables
# Deploy to staging branch
git push origin staging
# Vercel auto-deploys to staging-your-app.vercel.app
# Promote to production
git checkout main
git merge staging
git push origin main
Using Different Database Providers
While this guide focuses on Neon, OpenSaas Stack works with any PostgreSQL provider:
Supabase:
- Get connection string from Project Settings → Database
- Use pooler connection string for
DATABASE_URL
PlanetScale:
- Requires MySQL provider in config
- Get connection string from Dashboard
- No
DIRECT_URLneeded (PlanetScale uses different migration approach)
Railway:
- Provision PostgreSQL addon
- Copy connection string from Variables tab
- Use same pooling approach as Neon
Render:
- Create PostgreSQL database
- Get internal/external connection strings
- Use external for migrations, internal for app
Docker Deployment (Self-Hosting)
For deploying to your own infrastructure, see the Self-Hosting Guide (coming soon).
Next Steps
Now that your app is deployed:
- Set up monitoring and alerts (coming soon)
- Configure custom domain
- Add team members
- Set up CI/CD testing (coming soon)
- Optimize performance (coming soon)
Summary
You've successfully deployed your OpenSaas Stack application! Here's what you accomplished:
✅ Created a production PostgreSQL database on Neon ✅ Configured environment variables for production ✅ Deployed to Vercel with automatic deployments ✅ Set up database migrations ✅ Verified your deployment is working
Your app is now live and ready for users. Any pushes to your main branch will automatically deploy to production.