Skip to main content

Overview

Bounty is built with Next.js and can be deployed to various platforms. This guide covers deployment to Vercel (recommended) and self-hosted infrastructure.

Prerequisites

Before deploying, ensure you have:
1

Environment Variables

All required environment variables configured. See Environment Variables.
2

Database

PostgreSQL database set up and migrated. See Database Setup.
3

GitHub App

GitHub OAuth App and GitHub App configured with correct callback URLs.
4

External Services

Required services (Upstash Redis, GitHub, Better Auth) configured.

Deployment Options

Vercel provides the best experience for Next.js applications with:
  • Zero-configuration deployments
  • Automatic HTTPS and CDN
  • Serverless functions for API routes
  • Edge network for optimal performance
  • Built-in analytics and monitoring
  • Cron jobs for scheduled tasks

Self-Hosted

Deploy on your own infrastructure:
  • Full control over hosting environment
  • Use existing infrastructure
  • Deploy to any Node.js hosting platform
  • Custom domain and SSL configuration

Deploying to Vercel

Initial Setup

1

Create Vercel Account

Sign up at vercel.com using your GitHub account.
2

Import Repository

  1. Click “Add New Project”
  2. Import your Bounty repository from GitHub
  3. Vercel will auto-detect the Next.js framework
3

Configure Build Settings

Vercel should auto-detect these settings:
  • Framework Preset: Next.js
  • Root Directory: ./ (monorepo root)
  • Build Command: bun build (or use default)
  • Output Directory: .next (auto-detected)
  • Install Command: bun install
Vercel has native Bun support. It will automatically use Bun based on your package.json packageManager field.
4

Set Environment Variables

In Vercel dashboard → Project Settings → Environment Variables, add all variables from your .env file.
Use different values for Production, Preview, and Development environments.
Required Variables:
  • DATABASE_URL
  • BETTER_AUTH_SECRET
  • BETTER_AUTH_URL (use Vercel domain)
  • GITHUB_CLIENT_ID & GITHUB_CLIENT_SECRET
  • GITHUB_APP_* (all GitHub App variables)
  • UPSTASH_REDIS_REST_URL & UPSTASH_REDIS_REST_TOKEN
  • NEXT_PUBLIC_BASE_URL (use Vercel domain)
See complete list in Environment Variables.
5

Deploy

Click “Deploy” - Vercel will:
  1. Clone your repository
  2. Install dependencies with Bun
  3. Build the application
  4. Deploy to edge network
First deployment takes 2-5 minutes.

Post-Deployment Configuration

Update your GitHub OAuth App and GitHub App settings with your Vercel domain:GitHub OAuth App:
  • Authorization callback URL: https://your-app.vercel.app/api/auth/callback/github
GitHub App:
  • Callback URL: https://your-app.vercel.app/api/auth/callback/github
  • Webhook URL: https://your-app.vercel.app/api/webhooks/github
Environment Variables: Update in Vercel dashboard:
BETTER_AUTH_URL="https://your-app.vercel.app"
NEXT_PUBLIC_BASE_URL="https://your-app.vercel.app"
  1. Go to Project Settings → Domains
  2. Add your custom domain (e.g., bounty.yourdomain.com)
  3. Follow Vercel’s DNS configuration instructions
  4. Update environment variables with new domain:
    BETTER_AUTH_URL="https://bounty.yourdomain.com"
    NEXT_PUBLIC_BASE_URL="https://bounty.yourdomain.com"
    
  5. Update OAuth callback URLs in GitHub to use new domain
Bounty includes cron job configuration in vercel.json:
{
  "crons": [
    {
      "path": "/api/cron/cleanup-sessions",
      "schedule": "0 2 * * *"
    }
  ]
}
This runs session cleanup daily at 2 AM UTC.Protect Cron Endpoints: Set CRON_SECRET environment variable and verify in your cron handlers.
Test webhook delivery:
  1. GitHub Webhooks: Trigger test event in GitHub App settings
  2. Stripe Webhooks: Use Stripe CLI or dashboard to send test event
  3. Check Vercel Functions logs for successful processing
All webhooks should be sent to:
  • GitHub: https://your-domain.com/api/webhooks/github
  • Stripe: https://your-domain.com/api/webhooks/stripe

Vercel Configuration File

The vercel.json file in the repository root configures Vercel-specific settings:
{
  "build": {
    "env": {
      "SKIP_ENV_VALIDATION": "true"
    }
  },
  "crons": [
    {
      "path": "/api/cron/cleanup-sessions",
      "schedule": "0 2 * * *"
    }
  ]
}
Configuration Details:
  • SKIP_ENV_VALIDATION - Allows build to use Vercel environment variables
  • crons - Defines scheduled tasks (Hobby/Pro plans only)

Monitoring on Vercel

Deployment Logs

View build and deployment logs in Vercel dashboard → Deployments → [deployment] → Building

Function Logs

Monitor serverless function execution in Vercel dashboard → Deployments → [deployment] → Functions

Analytics

Track performance and usage in Vercel dashboard → Analytics (requires Pro plan)

Speed Insights

Monitor Core Web Vitals in Vercel dashboard → Speed Insights (requires Pro plan)

Self-Hosted Deployment

Building for Production

1

Install Dependencies

bun install
2

Set Environment Variables

Create .env.production with all required variables:
DATABASE_URL="postgresql://..."
BETTER_AUTH_SECRET="..."
BETTER_AUTH_URL="https://your-domain.com"
# ... all other variables
3

Run Database Migrations

bun db:migrate
4

Build Application

bun build
This runs:
  • turbo build - Builds all apps and packages
  • Type checking
  • Next.js production build
  • Asset optimization
Build output will be in apps/web/.next/

Deployment Options

Create a Dockerfile for containerized deployment:
FROM oven/bun:1.2.17 AS base
WORKDIR /app

# Install dependencies
FROM base AS deps
COPY package.json bun.lockb ./
COPY apps/web/package.json ./apps/web/
COPY packages/*/package.json ./packages/*/
RUN bun install --frozen-lockfile

# Build application
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN bun build

# Production image
FROM base AS runner
ENV NODE_ENV=production

COPY --from=builder /app/apps/web/.next ./apps/web/.next
COPY --from=builder /app/apps/web/public ./apps/web/public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

EXPOSE 3000
ENV PORT 3000

CMD ["bun", "start"]
Build and Run:
# Build image
docker build -t bounty-app .

# Run container
docker run -p 3000:3000 \
  --env-file .env.production \
  bounty-app

SSL/TLS Configuration

For self-hosted deployments, set up SSL certificates: Using Let’s Encrypt (Certbot):
# Install Certbot
sudo apt install certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d bounty.yourdomain.com

# Auto-renewal (runs twice daily)
sudo systemctl enable certbot.timer

Build Scripts Reference

All build scripts are defined in package.json:
{
  "scripts": {
    "dev": "dotenv -- turbo dev --filter='!@bounty/discord-bot'",
    "start": "dotenv -- turbo start",
    "build": "dotenv -- turbo build",
    "check-types": "dotenv -- turbo check-types",
    "db:push": "dotenv -- turbo -F @bounty/db db:push",
    "db:migrate": "dotenv -- turbo -F @bounty/db db:migrate"
  }
}
# Start development server
bun dev

# Start web app only
bun dev:web

# Type checking
bun check-types

Health Checks

Implement health check endpoint for monitoring:
// app/api/health/route.ts
import { db } from '@bounty/db';

export async function GET() {
  try {
    // Check database connectivity
    await db.execute('SELECT 1');
    
    return Response.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      services: {
        database: 'connected',
        redis: 'connected' // Add Redis check
      }
    });
  } catch (error) {
    return Response.json(
      { status: 'unhealthy', error: error.message },
      { status: 503 }
    );
  }
}
Access at: https://your-domain.com/api/health

Troubleshooting

Common Issues:
  • Missing environment variables during build
  • Type errors in TypeScript
  • Dependency conflicts
Solutions:
  • Set SKIP_ENV_VALIDATION=true for build
  • Run bun check-types locally first
  • Clear node_modules and reinstall: rm -rf node_modules && bun install
Common Issues:
  • Database connection errors
  • Missing environment variables
  • OAuth redirect mismatches
Solutions:
  • Verify DATABASE_URL is correct and accessible
  • Check all required env vars are set
  • Ensure callback URLs match environment
Common Issues:
  • GitHub webhooks timing out
  • Invalid webhook signatures
  • Firewall blocking requests
Solutions:
  • Check webhook endpoint is publicly accessible
  • Verify GITHUB_WEBHOOK_SECRET matches GitHub App
  • Review webhook delivery logs in GitHub App settings
Common Issues:
  • Slow database queries
  • High memory usage
  • Rate limiting
Solutions:
  • Add database indexes for frequently queried columns
  • Increase serverless function memory (Vercel)
  • Configure Redis rate limiting properly
  • Use database connection pooling

Production Checklist

Before going live, verify:
1

Environment

  • All environment variables set
  • Using production API keys (not test keys)
  • Secrets are strong and unique
  • NEXT_PUBLIC_EARLY_ACCESS_ENABLED set appropriately
2

Database

  • Database migrations applied
  • Backups configured
  • Connection pooling enabled
  • SSL/TLS enabled
3

OAuth & Webhooks

  • GitHub OAuth callbacks match domain
  • GitHub App webhooks configured
  • Stripe webhooks set up (if using payments)
  • Discord webhooks tested (if using)
4

Security

  • HTTPS enabled
  • Secrets not committed to git
  • Rate limiting configured
  • CORS settings appropriate
5

Monitoring

  • Error tracking (Sentry) configured
  • Analytics (PostHog) enabled
  • Health check endpoint working
  • Logs being collected
6

Testing

  • User signup/login works
  • GitHub integration functional
  • Bounty creation/submission works
  • Payments processing (if enabled)

Continuous Deployment

Vercel (Automatic)

Vercel automatically deploys:
  • Production: Commits to main branch
  • Preview: Pull requests and other branches

GitHub Actions (Self-Hosted)

Set up automated deployments:
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: oven-sh/setup-bun@v1
        with:
          bun-version: 1.2.17
      
      - name: Install dependencies
        run: bun install
      
      - name: Run migrations
        run: bun db:migrate
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
      
      - name: Build application
        run: bun build
        env:
          SKIP_ENV_VALIDATION: true
      
      - name: Deploy to server
        run: |
          rsync -avz --delete \
            --exclude '.env*' \
            --exclude 'node_modules' \
            ./ user@your-server:/var/www/bounty/
          
          ssh user@your-server 'cd /var/www/bounty && pm2 restart bounty'

Next Steps

Installation Guide

Set up local development environment

API Reference

Explore Bounty’s API endpoints

Environment Variables

Configure your environment

GitHub Repository

View source code and report issues

Build docs developers (and LLMs) love