Skip to main content
This guide covers best practices for deploying Toots in production environments, including security, performance, and monitoring recommendations.

Build configuration

Build script

Toots uses the following build script defined in apps/web/package.json:
{
  "scripts": {
    "build": "prisma generate && prisma migrate deploy && next build"
  }
}
This ensures:
  1. Prisma client is generated
  2. Database migrations are applied
  3. Next.js builds the production bundle

Environment variables

In production, ensure all required environment variables are set:
DATABASE_URL=postgresql://user:password@host:5432/database
BETTER_AUTH_SECRET=your_production_secret
BETTER_AUTH_URL=https://your-domain.com
GOOGLE_GENERATIVE_AI_API_KEY=your_api_key
Never commit .env files to version control. Use secret management tools like AWS Secrets Manager, HashiCorp Vault, or your platform’s secret storage.

Database configuration

Connection pooling

For production PostgreSQL, use connection pooling to handle concurrent requests efficiently:
# Direct connection
DATABASE_URL=postgresql://user:password@host:5432/database

# With pgBouncer or connection pooler
DATABASE_URL=postgresql://user:password@pooler-host:6543/database

Migration strategy

1

Run migrations before deployment

Always apply migrations before deploying new application code:
pnpm --filter web db:generate
pnpm --filter web db:migrate
Or use Prisma’s deploy command for production:
cd apps/web
npx prisma migrate deploy
2

Backup database

Create a backup before running migrations:
pg_dump -h host -U user -d database > backup_$(date +%Y%m%d_%H%M%S).sql
3

Verify migration success

After deployment, verify the schema is correct:
npx prisma db pull

Database backups

Implement automated backups:
  • Frequency: Daily at minimum, more often for high-traffic applications
  • Retention: Keep at least 30 days of backups
  • Testing: Regularly test backup restoration

Security best practices

Authentication secrets

Generate a strong BETTER_AUTH_SECRET:
openssl rand -base64 32
Rotate secrets periodically and use different secrets for each environment.

Database credentials

  • Use strong, unique passwords
  • Limit database user permissions to only what’s needed
  • Enable SSL/TLS for database connections in production
  • Restrict database access to application servers only

HTTPS configuration

Always use HTTPS in production:
BETTER_AUTH_URL=https://your-domain.com  # Not http://
Use a reverse proxy (nginx, Caddy) or platform-provided SSL termination.

Performance optimization

Node.js configuration

Set appropriate Node.js memory limits:
NODE_OPTIONS=--max-old-space-size=4096

Next.js optimization

The build process automatically optimizes:
  • Static page generation
  • Image optimization
  • Code splitting
  • Minification
Consider enabling:
  • Output caching: Cache API responses and database queries
  • CDN integration: Serve static assets from a CDN
  • ISR (Incremental Static Regeneration): For semi-dynamic pages

Database optimization

  • Add indexes for frequently queried fields
  • Use database query caching where appropriate
  • Monitor slow queries with pg_stat_statements
  • Consider read replicas for high-traffic applications

Platform-specific deployment

Vercel

Toots can be deployed to Vercel with a managed PostgreSQL database:
1

Install Vercel CLI

npm i -g vercel
2

Configure environment variables

Add environment variables in the Vercel dashboard or via CLI:
vercel env add DATABASE_URL
vercel env add BETTER_AUTH_SECRET
vercel env add BETTER_AUTH_URL
vercel env add GOOGLE_GENERATIVE_AI_API_KEY
3

Deploy

vercel --prod

Railway

Railway provides managed PostgreSQL and automatic deployments:
  1. Connect your GitHub repository
  2. Add a PostgreSQL service
  3. Configure environment variables
  4. Railway automatically runs build and migrations

AWS / Cloud platforms

For AWS, Google Cloud, or Azure:
  1. Use managed PostgreSQL (RDS, Cloud SQL, Azure Database)
  2. Deploy containers to ECS, Cloud Run, or App Service
  3. Use load balancers for high availability
  4. Configure auto-scaling based on traffic

Monitoring and logging

Application monitoring

Monitor key metrics:
  • Response times
  • Error rates
  • Database query performance
  • Memory and CPU usage
Consider tools like:
  • Sentry for error tracking
  • Datadog or New Relic for APM
  • LogRocket for session replay

Database monitoring

Track:
  • Connection pool usage
  • Query performance
  • Disk space
  • Replication lag (if using replicas)

Logging

Centralize logs using:
  • CloudWatch (AWS)
  • Cloud Logging (Google Cloud)
  • Papertrail or Logtail
  • ELK stack for self-hosted solutions

Health checks

Implement health check endpoints for load balancers and orchestration platforms:
// Example health check endpoint
export async function GET() {
  try {
    // Check database connection
    await prisma.$queryRaw`SELECT 1`
    return Response.json({ status: 'healthy' })
  } catch (error) {
    return Response.json({ status: 'unhealthy' }, { status: 503 })
  }
}

Scaling considerations

Horizontal scaling

Toots is stateless and can scale horizontally:
  • Run multiple application instances behind a load balancer
  • Use sticky sessions if needed for WebSocket connections
  • Share session state via database or Redis

Database scaling

For high traffic:
  1. Vertical scaling: Increase database instance size
  2. Read replicas: Route read queries to replicas
  3. Connection pooling: Use pgBouncer or AWS RDS Proxy
  4. Caching: Add Redis for frequently accessed data

Rollback strategy

Prepare for rollbacks:
  1. Version control: Tag releases in Git
  2. Database migrations: Test rollback migrations
  3. Blue-green deployment: Run old and new versions simultaneously
  4. Feature flags: Disable new features without redeploying

Checklist

Before going to production:
  • All environment variables are set securely
  • Database backups are configured and tested
  • HTTPS is enabled
  • Authentication secrets are strong and unique
  • Database connections use SSL
  • Monitoring and logging are configured
  • Health check endpoints are implemented
  • Error tracking is set up
  • Load testing has been performed
  • Rollback procedure is documented
  • On-call rotation is established (if applicable)

Build docs developers (and LLMs) love