OpenCall

Environment variables

Complete reference — where each value comes from.

This is the quick reference plus a ready-to-copy .env.example.

Paste the block below into the variables tab of the service you picked. On Render or Railway, pasting all of it saves each key as its own table row!

# Discord OAuth — the first login (empty database) becomes ADMIN automatically.
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
NEXTAUTH_SECRET=
NEXTAUTH_URL=http://localhost:3000

# LiveKit
LIVEKIT_URL=
LIVEKIT_API_KEY=
LIVEKIT_API_SECRET=

# Postgres
DATABASE_URL=

# Storage (optional — without it, chat has no image attachments).
# R2 is the default; for any other S3 endpoint fill in R2_ENDPOINT/R2_REGION
# instead of R2_ACCOUNT_ID.
R2_ACCOUNT_ID=
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET=
NEXT_PUBLIC_R2_PUBLIC_BASE_URL=
R2_ENDPOINT=
R2_REGION=

# Infra dashboard (optional, self-host only)
SERVER_METRICS_INGEST_SECRET=
VPS_SSH_HOST=
VPS_SSH_PORT=22
VPS_SSH_USER=
VPS_SSH_PRIVATE_KEY=

# General
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_apiBaseUrl=http://localhost:3000

# Optional
NEXT_PUBLIC_RTC_ENABLED=
APP_COMMIT_SHA=
GIPHY_API_KEY=

Each group below is detailed on its own page.

Discord and session (details)

VariableNotes
DISCORD_CLIENT_ID
DISCORD_CLIENT_SECRET
NEXTAUTH_SECRETopenssl rand -base64 32
NEXTAUTH_URLThe app's public URL

The first account to sign in on an empty database becomes ADMIN — there is no variable for it.

LiveKit (Cloud or self-host)

VariableNotes
LIVEKIT_URLwss://... — same format for cloud and self-host
LIVEKIT_API_KEY
LIVEKIT_API_SECRET

Postgres (details)

VariableNotes
DATABASE_URL

General

VariableNotes
NEXT_PUBLIC_APP_URLSame URL as NEXTAUTH_URL
NEXT_PUBLIC_apiBaseUrlAlways the same as NEXT_PUBLIC_APP_URL — Server Actions and Server Components call the app's own API through this absolute URL

Miss this variable and the admin panel breaks

Without NEXT_PUBLIC_apiBaseUrl the admin and user Server Actions fetch undefined/api/... and fail. It is a NEXT_PUBLIC_* variable, so it is baked into the bundle at build time — setting it later and restarting the service does not fix it, it needs a new deploy/build.

Storage (details, optional)

Without these the app still boots — it just does not accept image attachments in chat. The R2_ prefix names the slot, not the provider: the same variables serve Cloudflare R2 and Neon Object Storage.

VariableNotes
R2_BUCKET
R2_ACCESS_KEY_ID
R2_SECRET_ACCESS_KEY
NEXT_PUBLIC_R2_PUBLIC_BASE_URLGoes into the client bundle, not a secret
R2_ACCOUNT_IDR2 only — the endpoint is derived from it
R2_ENDPOINTAny non-R2 S3 endpoint (Neon, MinIO). Setting it also switches the client to path-style
R2_REGIONOnly with R2_ENDPOINT. Defaults to auto, which is what R2 requires; Neon needs the project's real region

Optional

VariableNotes
GIPHY_API_KEYEnables the GIF button in chat. Create an app at developers.giphy.com. Never NEXT_PUBLIC_* — the search goes through the server
NEXT_PUBLIC_RTC_ENABLEDSet to false, 0 or off to disable voice/video for the whole deploy. Anything else (including unset) keeps it on
APP_COMMIT_SHAThe deploy's commit. With it, tabs open during a new deploy get an "update the page" notice. On Railway use RAILWAY_GIT_COMMIT_SHA

Infra dashboard (optional — self-host only)

VariableNotes
SERVER_METRICS_INGEST_SECRETThe same value on the app and on the VPS
VPS_SSH_HOSTAlso the flag that turns on the admin's "Infra" tab
VPS_SSH_PORTUsually 22
VPS_SSH_USERA restricted user, not root
VPS_SSH_PRIVATE_KEYPEM private key

VULTR_API_KEY (if you use Vultr) does not go in the app — it lives only on the VPS, in the bandwidth collector.

On this page