Skip to content

Environment Variables & Config Guide ​

How environment variables are managed in the Oktivo backend.


How It Works ​

Environment variables are loaded from AWS Secrets Manager at startup (or from local env/ files when USE_LOCAL_ENV=true). The values are injected into process.env / os.environ before any config module reads them.

env/shared.env + env/{service}.env   (local, USE_LOCAL_ENV=true)
         OR —
AWS Secrets Manager                  (USE_LOCAL_ENV=false)
    ↓
secrets loader injects into process.env / os.environ
    ↓
src/config/index.ts (TypeScript) / config.py (Python)
    ↓
controllers / services / etc.

Key Behavior ​

  • USE_LOCAL_ENV=true → loads from env/shared.env + env/{service}.env (default in docker-compose.dev.yml)
  • USE_LOCAL_ENV=false → fetches from AWS Secrets Manager
  • Docker-compose environment: overrides always win (setdefault / !process.env[key])
  • Secrets are fetched once at startup and cached for the process lifetime

Rules ​

  1. Never use process.env in controllers, services, or models. Always import from config.
  2. Add new env vars to config/index.ts so they're typed, trimmed, and have defaults.
  3. Add new env vars to the matching env/*.env.example file with a comment explaining what it does.
  4. Never put inline comments on the same line as a value. Dotenv does NOT strip them.
  5. Never put spaces around = in .env files.

.env Syntax ​

bash
# ✅ Correct
MY_KEY=some_value

# ✅ Comment on its own line is fine
# This key does X
MY_KEY=some_value

# ❌ WRONG inline comment becomes part of the value
MY_KEY=some_value   # this is a comment
# MY_KEY will be: "some_value   # this is a comment"

# ❌ WRONG spaces around = can cause issues
MY_KEY = some_value

Adding a New Environment Variable ​

Step 1: Add to AWS Secrets Manager (dev environment) ​

Add the key-value pair to the appropriate secret in the AWS Console:

  • Shared across services → oktivo/dev/shared
  • Client backend only → oktivo/dev/client-backend
  • Agent only → oktivo/dev/agent
  • Analysis only → oktivo/dev/analysis

Step 2: Add to local env file AND example file ​

bash
# env/shared.env (real value gitignored)
MY_NEW_KEY=actual_value

# env/shared.env.example (placeholder committed to git)
# Description of what this key does
MY_NEW_KEY=

Step 3: Add to src/config/index.ts (client_backend) ​

typescript
export const config = {
  // ... existing config ...

  // Add under the relevant section, with .trim() and a sensible default
  myNewKey: process.env.MY_NEW_KEY?.trim() || "default_value",
} as const;

Step 4: Use in your code ​

typescript
import { config } from "../config/index.js";

// ✅ Correct
const value = config.myNewKey;

// ❌ Wrong never do this
const value = process.env.MY_NEW_KEY;

Step 5: Add to stage/prod secrets before merging ​

The secrets-sync-check CI workflow will block your PR if the key is missing in the target environment. Add it to oktivo/stage/* before merging to stage, and oktivo/prod/* before merging to main.

Config Sections ​

SectionEnv VarsPurpose
CorePORT, MONGO_URI, DB_NAME, NODE_ENVServer basics
AuthACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET, *_EXPIRYJWT tokens
LiveKitLIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRETVoice infrastructure
AWS S3AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_RECORDING_BUCKETCall recordings
RedisREDIS_URLBullMQ queues, campaign state
EmailEMAIL_PROVIDER, EMAIL_FROM, RESEND_API_KEY, SES_REGIONEmail service
SuperAdminSUPERADMIN_EMAIL, SUPERADMIN_API_SECRETPlatform admin

Trimming ​

All email config values are .trim()'d in config/index.ts to prevent whitespace issues from .env files. If you add a new env var that could have accidental whitespace (API keys, URLs), add .trim():

typescript
myApiKey: process.env.MY_API_KEY?.trim() || "",

Last updated: