Deployment Guide

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:

  1. Setting up a production database (Neon PostgreSQL)
  2. Configuring environment variables
  3. Deploying to Vercel
  4. Running database migrations
  5. 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.

  1. Sign in to Neon Console

  2. 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"
  3. 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
  4. 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:

bash
# .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:

typescript
export default config({
  db: {
    provider: 'postgresql',
    url: process.env.DATABASE_URL!,
    directUrl: process.env.DIRECT_URL, // Add this line
  },
  lists: {
    // ... your lists
  },
})

Then regenerate:

bash
pnpm generate

Environment Variables for Better Auth (If Using)

If you're using @opensaas/stack-auth, you'll need additional variables:

bash
# .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:

bash
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)

  1. Install Vercel CLI
bash
npm install -g vercel
  1. Login to Vercel
bash
vercel login
  1. Deploy from Project Root
bash
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
  1. Add Environment Variables
bash
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
  1. Deploy to Production
bash
vercel --prod

Option B: Deploy with Vercel Dashboard

  1. Push to Git
bash
git add .
git commit -m "Initial deployment"
git push origin main
  1. Import Project in Vercel

    • Go to vercel.com/new
    • Click "Import Project"
    • Select your Git repository
    • Click "Import"
  2. 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)
  3. Add Environment Variables

    • Click "Environment Variables"
    • Add each variable:
      • DATABASE_URL → Your pooled connection string
      • DIRECT_URL → Your direct connection string
      • BETTER_AUTH_SECRET → Your random secret (if using auth)
      • BETTER_AUTH_URLhttps://your-app.vercel.app (update after first deploy)
      • Add any OAuth credentials if using social login
  4. 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:

bash
# 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:

bash
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):

bash
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:

bash
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

  1. Visit Your App

    • Go to your Vercel deployment URL
    • You should see your app running
  2. Test Database Connectivity

    • If you have an admin UI, try creating a record
    • Verify it appears in Prisma Studio
    • Check for any console errors
  3. Check Vercel Logs

    • Go to your project in Vercel Dashboard
    • Click "Deployments" → Select latest deployment → "Functions"
    • View logs for any errors
  4. Update Better Auth URL (If Using)

    • Go to Vercel Dashboard → Your Project → Settings → Environment Variables
    • Update BETTER_AUTH_URL to your production URL (e.g., https://your-app.vercel.app)
    • Redeploy: vercel --prod or push to Git

Continuous Deployment

Automatic Deployments

Once connected to Git, Vercel automatically deploys:

  • Production: Pushes to main branch → your-app.vercel.app
  • Preview: Pull requests → your-app-git-branch.vercel.app

Deploy Workflow

bash
# 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:

  1. Add Migration Step to Vercel
    • In package.json, update build script:
json
{
  "scripts": {
    "build": "prisma generate && prisma migrate deploy && next build"
  }
}
  1. Ensure DIRECT_URL is Set
    • Add DIRECT_URL to Vercel environment variables
    • This allows migrations during build

Alternative: Run migrations manually before deploying:

bash
# 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

Environment Variables Management

Never commit secrets to Git:

  • Add .env*.local to .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:

bash
# 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:

typescript
// 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_SECRET is 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_URL is correct (copy from Neon Console)
  • Check sslmode=require is 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=10 to connection string:
    typescript
    postgresql://...?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 resolve to mark failed migrations
  • For destructive changes, backup data first

"Authentication not working"

Symptoms: Better Auth login fails in production

Solutions:

  • Verify BETTER_AUTH_URL matches your production domain
  • Check BETTER_AUTH_SECRET is 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
  • Check browser console for CORS errors

"Build failed"

Symptoms: Vercel deployment fails during build

Solutions:

  • Check Vercel build logs for specific error
  • Ensure pnpm generate runs successfully locally
  • Verify all dependencies are in package.json (not just devDependencies)
  • Check Node.js version matches Vercel (use .nvmrc or package.json engines 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:

  1. Check OpenSaas Stack GitHub Issues
  2. Search Vercel Docs
  3. Check Neon Docs
  4. Ask in Discord/Community (if available)

Advanced Topics

Custom Domains

  1. Add Domain in Vercel

    • Go to Project Settings → Domains
    • Add your custom domain (e.g., app.example.com)
    • Follow DNS configuration instructions
  2. Update Better Auth URL

    • Update BETTER_AUTH_URL environment variable
    • Update OAuth redirect URLs in provider settings

Multi-Environment Setup

For staging + production:

bash
# 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_URL needed (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:

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.