Environment Variables
All env var validation lives in lib/env/index.ts. Validation is skipped in production (NODE_ENV === 'production'), so missing or malformed vars will cause runtime failures, not build-time failures. Verify your production environment carefully.
Copy example.env as a starting point:
cp example.env .env.localRequired — server-side
These vars are never exposed to the browser. All are required at startup.
| Variable | Type | Description |
|---|---|---|
GITHUB_APP_ID | string (numeric) | The GitHub App’s numeric ID, shown on the App settings page |
GITHUB_PRIVATE_KEY | string (PEM) | Full RSA private key including -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- lines. Newlines must be preserved. |
GITHUB_CLIENT_ID | string | OAuth Client ID from the GitHub App settings page |
GITHUB_CLIENT_SECRET | string | OAuth Client secret — generate one on the GitHub App settings page |
GITHUB_APP_NAME | string | The app’s slug as it appears in https://github.com/apps/<slug> — used to build installation URLs |
SUPABASE_SERVICE_ROLE_KEY | string | Service role key from Supabase project settings. Has full DB access — never expose to the browser. |
Required — public (client-side)
These are bundled into the browser build. Do not put secrets here.
| Variable | Type | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | URL string | Supabase project URL, e.g. https://<ref>.supabase.co |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY | string | Supabase anon/public key — safe to expose, subject to RLS |
NEXT_PUBLIC_APP_URL | URL string | Base URL of the app. Default: http://localhost:3000. Set to your Vercel deployment URL in production. |
Optional — security-critical in production
These have derived fallbacks that are intentionally weak. Always set them explicitly in production.
| Variable | Default if unset | Risk |
|---|---|---|
AUTH_SESSION_SECRET | Derived from GITHUB_CLIENT_SECRET + GITHUB_APP_ID | Session tokens can be forged if the derivation is known |
TOKEN_ENCRYPTION_KEY | Derived from GITHUB_CLIENT_SECRET + GITHUB_APP_ID | Stored GitHub tokens can be decrypted if the derivation is known |
GITHUB_WEBHOOK_SECRET | Empty string | Webhook signature verification is skipped entirely — any HTTP client can send fake events |
Optional — Redis caching
Omitting these vars disables Redis. The app falls back to in-memory LRU caching only. See Caching for how the layers interact.
| Variable | Description |
|---|---|
UPSTASH_REDIS_REST_URL | Upstash Redis REST endpoint, e.g. https://us1-...upstash.io |
UPSTASH_REDIS_REST_TOKEN | Authentication token for the Upstash Redis instance |
REDIS_CACHE_PREFIX | String prefix for all Redis keys. Default: gh-org-tool. Useful if you share a Redis instance across environments. |
Optional — debug
| Variable | Description |
|---|---|
ENABLE_DEBUG_ROUTES | Set to true to enable /api/debug/* routes in production. These routes expose internal state and should only be used temporarily. |
Notes on GITHUB_PRIVATE_KEY
The private key is a multi-line PEM block. In a .env.local file, wrap it in double quotes and preserve newlines literally:
GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
...
-----END RSA PRIVATE KEY-----"In Vercel, paste the full PEM including the header and footer lines into the environment variable field. Vercel handles multi-line values correctly.
Production checklist
Before deploying:
-
AUTH_SESSION_SECRETis set to a random 32+ character string -
TOKEN_ENCRYPTION_KEYis set to a random 32+ character string -
GITHUB_WEBHOOK_SECRETis set and matches the value in GitHub App settings -
NEXT_PUBLIC_APP_URLmatches your deployment URL (no trailing slash) -
SUPABASE_SERVICE_ROLE_KEYis from production, not a dev project - Redis vars are set if you want caching beyond the process-local LRU