Operate

Self-hosting

Run the web app, API, and worker yourself.

OpenMerge is open source under the MIT license. The code is on GitHub, and this page covers what you need to run it yourself.

Architecture

ServiceRole
apps/webNext.js app: landing page, docs, sign-in, and dashboard.
apps/serverExpress API: GitHub OAuth, webhook verification, review sessions, and dashboard routes. Queues review jobs.
apps/workerProcesses review jobs: gathers context, runs the agents, and posts to GitHub. Run it separately from the API.
PostgreSQLUsers, installations, repositories, review sessions, and findings.
RedisThe review job queue.

Create a GitHub App

Create a GitHub App for your deployment, plus an OAuth app for dashboard sign-in, and point them at your URLs:

SettingValue
Webhook URLhttps://<api-host>/api/v1/webhook/github
Webhook eventsPull request and Installation
Setup URLhttps://<web-host>/setup
OAuth callback URLhttps://<web-host>/auth/github/callback

The app needs to read repository contents and pull requests and to write pull request comments. Generate a private key and a webhook secret, and keep both in your secret manager.

Environment variables

The API validates its environment at startup and exits with a clear error if something is missing. It reads apps/server/.env or a .env at the repository root.

API and worker

VariableStatusDescription
DATABASE_URLRequiredPostgreSQL connection string.
SERVER_JWT_SECRETRequiredSigns dashboard sessions (valid for seven days).
GITHUB_CLIENT_IDRequiredOAuth app client ID, used for sign-in.
GITHUB_CLIENT_SERVERRequiredOAuth app client secret.
GITHUB_CALLBACK_URLRequiredThe web app's /auth/github/callback URL.
GITHUB_APP_IDRequiredGitHub App ID.
GITHUB_APP_NAMERequiredGitHub App slug.
GITHUB_APP_CLIENT_IDRequiredGitHub App client ID.
GITHUB_APP_CLIENT_SECRETRequiredGitHub App client secret.
GITHUB_WEBHOOK_SECRETRequiredVerifies X-Hub-Signature-256 on incoming webhooks.
GITHUB_PRIVATE_KEYRequiredGitHub App private key (PEM).
GROQ_API_KEYRequiredModel provider used for reviews, and the fallback when Gemini is configured.
GEMINI_API_KEYOptionalWhen set, Gemini is tried first and Groq is used as the fallback.
REDIS_URLOptionalDefaults to redis://localhost:6379 in development. Required in production.
PORTOptionalAPI port. Defaults to 8000.

Web app

VariableStatusDescription
NEXT_PUBLIC_API_URLRequiredPublic URL of the API. Defaults to http://localhost:8000.
NEXT_PUBLIC_APP_URLRequiredPublic URL of the web app.

Allow your web origin

The API only accepts browser requests from the origins listed in apps/server/src/index.ts. Add your web app's URL there, or the dashboard cannot reach the API.

Local development

You need Bun and Docker. Start PostgreSQL and Redis, install dependencies, apply migrations, and run everything in watch mode:

bash
docker compose up -d                     # PostgreSQL on 5433, Redis on 6379
bun install
cd packages/database && bun run db:migrate:dev && cd ../..
bun run dev                              # web, API, and worker
The Compose file publishes PostgreSQL on host port 5433, so point DATABASE_URL at localhost:5433.

To run a single app, filter by workspace:

bash
bun run dev --filter=web
bun run dev --filter=server
bun run dev --filter=worker

Production checklist

  • Run the API and the worker as separate, independently restartable services.
  • Use managed PostgreSQL and Redis with persistent storage and backups.
  • Set NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_API_URL, and GITHUB_CALLBACK_URL to their public HTTPS addresses.
  • Apply migrations on each deploy with bun --cwd packages/database run db:migrate:deploy.
  • Add health checks, structured logs, queue monitoring, and alerts for failed jobs.
  • Rotate any exposed private key, webhook secret, OAuth secret, or model key immediately.

Something unclear or out of date? Open an issue.