Deployment
Deploy Respondeo to production
Deployment
This guide covers deploying Respondeo to various environments.
Prerequisites
- Node.js runtime installed
- A PostgreSQL database (or SQLite for simple deployments)
- An OIDC provider for authentication (see authentication.md)
Environment Variables
Copy .env.example to .env.local (development) or .env (production) and configure all required variables:
cp .env.example .env.localRequired Variables
| Variable | Description |
|---|---|
NEXT_PUBLIC_APP_URL | Public URL where the app is hosted |
BETTER_AUTH_SECRET | Secret key for session encryption (min 32 chars) |
BETTER_AUTH_URL | URL for the auth service (usually same as app URL) |
OIDC_CLIENT_ID | OAuth client ID from your identity provider |
OIDC_CLIENT_SECRET | OAuth client secret |
OIDC_ISSUER | OIDC issuer URL (e.g., https://auth.example.com) |
OIDC_PROVIDER_ID | Unique identifier for your OIDC provider (e.g., "my-idp") |
NEXT_PUBLIC_OIDC_PROVIDER_ID | Public provider ID (must match OIDC_PROVIDER_ID) |
Optional Variables
| Variable | Default | Description |
|---|---|---|
DB_DIALECT | sqlite | Database type: sqlite or postgres |
DATABASE_URL | quiz.db | Database connection string |
RBAC_* | See below | Role-based access control settings |
See database.md for database setup and rbac.md for access control configuration.
Local Development
# Install dependencies
pnpm install
# Set up database
pnpm db:push
# Start development server
pnpm devThe app will be available at http://localhost:3000.
Production Build
# Build the application
pnpm build
# Start production server
pnpm startDocker Deployment
Using Docker Compose
The repository includes a compose.yaml for easy deployment with PostgreSQL:
# Start all services
docker compose up -d
# View logs
docker compose logs -f
# Stop services
docker compose downBuilding the Docker Image
# Build the image
docker build -t quiz-app .
# Run with environment variables
docker run -d \
-p 3000:3000 \
-e NEXT_PUBLIC_APP_URL=https://quiz.example.com \
-e BETTER_AUTH_SECRET=your-secret-key \
-e BETTER_AUTH_URL=https://quiz.example.com \
-e OIDC_CLIENT_ID=your-client-id \
-e OIDC_CLIENT_SECRET=your-client-secret \
-e OIDC_ISSUER=https://auth.example.com \
-e DB_DIALECT=postgres \
-e DATABASE_URL=postgresql://user:pass@db:5432/quiz \
quiz-appVercel Deployment
The app is optimized for Vercel deployment:
- Push your repository to GitHub
- Import the project in Vercel Dashboard
- Configure environment variables in Vercel's project settings
- Deploy
Vercel Environment Variables
Set all required environment variables in Settings → Environment Variables:
NEXT_PUBLIC_APP_URL- Your Vercel deployment URLBETTER_AUTH_SECRET- Generate withopenssl rand -base64 32BETTER_AUTH_URL- Same asNEXT_PUBLIC_APP_URLOIDC_*- Your OIDC provider credentialsDATABASE_URL- PostgreSQL connection string (use Vercel Postgres or external)
Database Options for Vercel
- Vercel Postgres - Managed PostgreSQL, integrates automatically
- Neon - Serverless Postgres with generous free tier
- Supabase - PostgreSQL with additional features
- PlanetScale - MySQL-compatible (requires schema changes)
Co-locate functions with your database. apps/web/vercel.json pins
regions: ["iad1"] (Washington, D.C.) to match a Neon database in AWS
us-east-1. If you host the database elsewhere, change this — otherwise every
query on every request pays the round trip between the two regions.
Rate limiting on Vercel
Configure REDIS_URL (or VALKEY_URL). Vercel runs many concurrent function
instances, and without a shared store each one keeps its own rate limit
counters — so RATE_LIMIT_AI_GLOBAL=10 becomes "10 per instance per hour"
rather than a real cap on AI provider spend. See Caching.
Migrations on Vercel
Migrations run as part of the build script. On Vercel they are applied for
production deployments only, so a preview build cannot migrate a schema that
production is still serving against — the common case when previews and
production share one DATABASE_URL.
If your previews point at their own branch database and you want them migrated
too, set RUN_MIGRATIONS=true for the Preview environment.
Monorepo build settings
Each app is its own Vercel project with Root Directory set to apps/web or
apps/docs. Vercel reads vercel.json from that directory, so per-app settings
belong in apps/web/vercel.json and apps/docs/vercel.json — a vercel.json
at the repository root is ignored under this layout.
Both apps set installCommand: pnpm install --frozen-lockfile, so a stale
lockfile fails the build instead of silently resolving different versions than
CI did.
Neither sets an ignoreCommand. Skipping builds for commits that don't touch an
app is handled by Vercel's built-in Settings → Git → Skip unaffected
projects, which supersedes the deprecated turbo-ignore. Note that an
ignoreCommand in vercel.json takes precedence over that setting, so don't
reintroduce one without removing the toggle.
Function duration
AI quiz generation runs as a server action on the quiz create and edit routes,
which set maxDuration = 300. A long generation with image inputs can otherwise
be cut off by the platform default mid-request.
Health Checks
The app automatically checks database connectivity. If the database is unavailable, pages will display an error message rather than crashing.
Reverse Proxy Configuration
Nginx
server {
listen 80;
server_name quiz.example.com;
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;
proxy_cache_bypass $http_upgrade;
}
}Caddy
quiz.example.com {
reverse_proxy localhost:3000
}Troubleshooting
Application won't start
- Check all required environment variables are set
- Verify database connectivity with
pnpm db:studio - Check logs for specific error messages
Authentication issues
- Verify OIDC issuer URL is accessible
- Check callback URL is configured in your identity provider
- Ensure
BETTER_AUTH_URLmatches your deployment URL
Database connection errors
- Verify
DATABASE_URLformat is correct - Check database server is running and accessible
- Ensure database user has proper permissions
See database.md for detailed database troubleshooting.