Skip to main content

Environment Variables

OpenATS keeps its settings in two files: backend/.env and frontend/.env. Each has an example file beside it that you can copy.

Both programs check their settings when they start. If something required is missing, they stop and tell you which value to fix, so you'll know right away.

After changing a setting, restart the program that uses it. Anything starting with NEXT_PUBLIC_ is different: it's built into the website, so you'll need to run the build again as well.

Backend settings​

These go in backend/.env, and both the API and the worker read them.

Core​

VariableRequiredWhat it's for
DATABASE_URLYesYour PostgreSQL connection
REDIS_URLNoYour Redis connection. Defaults to redis://localhost:6379
FRONTEND_URLYesThe address people use to open OpenATS. Every link in a candidate email starts with this, so in production it must be your public address
PORTNoThe API's port. Defaults to 8080
TRUST_PROXYNoHow many proxies sit in front of the API. Defaults to 1. See Deploy to Production
RUN_WORKER_IN_APINoSet to true to run the background worker inside the API, for hosting without a second service

Sign-in​

VariableRequiredWhat it's for
AUTH_JWKS_URLYesThe website's address followed by /api/auth/jwks
AUTH_ISSUERYesThe website's address. Must exactly match BETTER_AUTH_URL in the frontend
ENCRYPTION_KEYYesProtects saved Google connections. Must be 32 bytes in base64. Create one with openssl rand -base64 32

Don't change ENCRYPTION_KEY once people have connected their Google accounts, because their saved connections can no longer be read.

File storage​

All of these are required, and the backend won't start while any are empty.

VariableWhat it's for
R2_ENDPOINTYour storage address
R2_ACCESS_KEY_IDThe storage access key
R2_SECRET_ACCESS_KEYThe storage secret
R2_BUCKET_NAMEThe public bucket, for logos
R2_PUBLIC_URLThe public address of that bucket
R2_PRIVATE_BUCKET_NAMEThe private bucket, for CVs. Never turn on public access for this one

Email​

VariableRequiredWhat it's for
SMTP_HOSTYesYour mail server
SMTP_PORTNoDefaults to 587
SMTP_SECURENotrue for port 465, otherwise false
SMTP_USERNoYour mail server username
SMTP_PASSWORDNoYour mail server password
MAIL_FROMYesThe address emails come from
MAIL_FROM_NAMENoThe name emails come from

Optional features​

VariableWhat it's for
GEMINI_API_KEYLets you turn on AI CV analysis
GOOGLE_OAUTH_CLIENT_IDLets interviewers connect Google Calendar and Meet
GOOGLE_OAUTH_CLIENT_SECRETThe secret for the same Google client
GOOGLE_OAUTH_REDIRECT_URIThe API's address followed by /oauth/google/callback
RATE_LIMIT_APIRequests allowed per signed-in user every 15 minutes
RATE_LIMIT_EXPENSIVEUploads allowed per signed-in user every 15 minutes

Frontend settings​

These go in frontend/.env.

VariableRequiredWhat it's for
DATABASE_URLYesThe same database as the backend. The website uses it for sign-in
BETTER_AUTH_SECRETYesAt least 32 characters. Keep it the same across restarts, or everyone gets signed out
BETTER_AUTH_URLYesThe address people use to open OpenATS
OPENATS_API_URLYesThe API's address, as the website's server reaches it
NEXT_PUBLIC_API_URLYesThe API's address, as a visitor's browser reaches it
NEXT_PUBLIC_APP_URLNoYour public address, used in careers page links
AUTH_TRUSTED_PROXIESNoYour proxy addresses, so sign-in limits apply per person
SMTP_*, MAIL_FROM, MAIL_FROM_NAMENoUse the same values as the backend. Without them, invite and password reset emails aren't sent

Never put a secret in a NEXT_PUBLIC_ variable, because those are visible to anyone who opens the site.

The NEXT_PUBLIC_DEMO_* settings show demo sign-in details on the sign-in page. Leave them empty on a real installation.

Addresses that must match​

Most sign-in problems come from these not lining up. Here's a setup with the website at https://ats.example.com and the API at https://api.example.com:

# backend/.env
FRONTEND_URL=https://ats.example.com
AUTH_ISSUER=https://ats.example.com
AUTH_JWKS_URL=https://ats.example.com/api/auth/jwks

# frontend/.env
BETTER_AUTH_URL=https://ats.example.com
NEXT_PUBLIC_APP_URL=https://ats.example.com
NEXT_PUBLIC_API_URL=https://api.example.com
OPENATS_API_URL=https://api.example.com