A standalone GitHub App that provides merge queue functionality for any repository. Coordinates PR merges to prevent merge conflicts and ensure CI passes before merging.
- Automated queue processing - PRs are merged in order, one at a time
- Auto-rebase - Automatically updates PRs with latest base branch before merging
- CI verification - Waits for status checks to pass before merging
- Multiple triggers - Queue via label (
merge-queue) or comment (/merge) - Per-repo settings - Configure merge method, timeouts, and triggers per repository
- Audit trail - Full event history for compliance
- Multi-repo support - One installation works across all your repos
-
Go to GitHub Settings > Developer settings > GitHub Apps > New GitHub App
-
Configure:
- Name:
Your Merge Queue - Webhook URL:
https://your-domain.com/webhooks/github - Webhook Secret: Generate a secure secret
- Permissions:
- Repository: Contents (Read & Write), Pull requests (Read & Write), Commit statuses (Read)
- Organization: Members (Read)
- Events: Pull request, Issue comment, Installation
- Name:
-
Generate a private key and download it
# Environment variables
export DATABASE_URL="postgres://user:pass@host:5432/merge_queue"
export GITHUB_APP_ID="123456"
export GITHUB_PRIVATE_KEY_PATH="./private-key.pem"
export GITHUB_WEBHOOK_SECRET="your-webhook-secret"
# Run
go build -o merge-queue ./cmd/server
./merge-queueInstall your GitHub App on the organizations/repos you want to use it with.
Via Label:
Add the merge-queue label to a PR
Via Comment:
Comment /merge on the PR
Via API:
curl -X POST https://your-domain.com/api/v1/queue \
-H "Content-Type: application/json" \
-d '{"owner": "org", "repo": "repo", "pr_number": 123}'curl "https://your-domain.com/api/v1/queue?owner=org&repo=repo"curl -X PUT https://your-domain.com/api/v1/settings \
-H "Content-Type: application/json" \
-d '{
"owner": "org",
"repo": "repo",
"enabled": true,
"merge_method": "squash",
"require_ci_pass": true,
"auto_rebase": true,
"trigger_label": "merge-queue",
"trigger_comment": "/merge"
}'| Endpoint | Method | Description |
|---|---|---|
/healthz |
GET | Health check |
/webhooks/github |
POST | GitHub webhook receiver |
/api/v1/queue |
GET | Get queue for a repo |
/api/v1/queue |
POST | Add PR to queue |
/api/v1/queue/{id} |
DELETE | Remove from queue |
/api/v1/queue/{id}/retry |
POST | Retry failed item |
/api/v1/settings |
GET | Get repo settings |
/api/v1/settings |
PUT | Update repo settings |
/api/v1/events |
GET | Get queue events |
/api/v1/installations |
GET | List installations |
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
GITHUB_APP_ID |
Yes | GitHub App ID |
GITHUB_PRIVATE_KEY |
Yes* | PEM content (or use path) |
GITHUB_PRIVATE_KEY_PATH |
Yes* | Path to PEM file |
GITHUB_WEBHOOK_SECRET |
No | Webhook signature secret |
PORT |
No | Server port (default: 8080) |
*One of GITHUB_PRIVATE_KEY or GITHUB_PRIVATE_KEY_PATH is required.
| Setting | Default | Description |
|---|---|---|
enabled |
true | Enable/disable queue for repo |
merge_method |
merge | merge, squash, or rebase |
require_ci_pass |
true | Wait for CI before merge |
auto_rebase |
true | Update branch before merge |
delete_branch_on_merge |
true | Delete PR branch after merge |
max_queue_size |
50 | Max items in queue |
ci_timeout_minutes |
60 | CI wait timeout |
trigger_label |
merge-queue | Label to trigger queue |
trigger_comment |
/merge | Comment to trigger queue |
queued → processing → rebasing → waiting_ci → merging → merged
↓ ↓ ↓ ↓
failed failed failed failed
MIT