Skip to content

Brain Environment Variables

Brain reads configuration from process.env via @nestjs/config and a few direct lookups (apps/brain/src/main.ts, apps/brain/src/common/runtime/stage.ts, apps/brain/src/config/queue.config.ts). The BRAIN_*-prefixed variables in .env.example are mapped onto the unprefixed names that the service actually reads in docker-compose.yml. On Railway the same mapping happens via the service env config.

The canonical .env.example is at the repo root.

Var Required Default Source Purpose
BRAIN_STAGE yes development .env.example, Railway Resolved by getBrainStage() to production/staging/sandbox/development; PR previews containing -pr- map to sandbox.
RAILWAY_ENVIRONMENT_NAME platform — Railway runtime Stage fallback when BRAIN_STAGE is unset.
NODE_ENV yes production (compose) docker-compose.yml, Railway Final stage fallback.
PORT yes 3000 docker-compose.yml, main.ts HTTP listen port; main.ts binds to IPv6 dual-stack ::.
BRAIN_HTTP_PORT dev 3000 .env.example Local override only; service still reads PORT.
Var Required Default Source Purpose
DATABASE_URL yes — prisma/schema.prisma, Railway Pooled Prisma connection (Neon pgbouncer in prod).
DIRECT_DATABASE_URL yes (migrations) falls back to DATABASE_URL prisma/schema.prisma, docker-compose.yml Direct (non-pooled) connection for prisma migrate deploy.
BRAIN_DATABASE_URL dev — .env.example Mapped onto DATABASE_URL in compose.
BRAIN_DIRECT_DATABASE_URL optional locally, required with pooled Neon falls back to BRAIN_DATABASE_URL .env.example, docker-compose.yml Mapped onto DIRECT_DATABASE_URL in compose. Set it when BRAIN_DATABASE_URL uses a pooler.
DATABASE_REPLICA_URL no empty (every query on the primary) Railway (Neon read replica, pooled endpoint) Allowlisted read-only routes read this replica; everything else stays on the primary. Inherits DATABASE_URL’s ?schema= when it has none; its pool is sized by its own connection_limit, not BRAIN_DB_POOL_*. See Neon read replicas (withReadReplica in apps/brain/src/modules/application/prisma/services/prisma.service.ts).
BRAIN_DATABASE_REPLICA_URL dev empty .env.example, docker-compose.yml Mapped onto DATABASE_REPLICA_URL in compose.

Brain owns the fennec schema in the shared sirloin DB. See Data Model.

Var Required Default Source Purpose
REDIS_HOST yes localhost apps/brain/src/config/queue.config.ts BullMQ connection host.
REDIS_PORT yes 6379 queue.config.ts BullMQ connection port.
REDIS_PASSWORD optional — queue.config.ts Auth where Redis is password-protected.

family: 0 is set so dual-stack IPv4/IPv6 resolution works on Railway’s private network.

Var Required Default Source Purpose
CLERK_PUBLISHABLE_KEY yes — Clerk dashboard Frontend Clerk identifier.
CLERK_SECRET_KEY yes — Clerk dashboard Server-side token verification (@clerk/backend).
AUTHORIZED_KEYS yes — Generated; rotated per-stage Comma-separated list of API keys accepted by @ApiKeyRoute() endpoints. See Auth Model “API key scopes”.
BRAIN_CLERK_PUBLISHABLE_KEY / BRAIN_CLERK_SECRET_KEY / BRAIN_AUTHORIZED_KEYS dev — .env.example Mapped onto the unprefixed names by compose.
FRONTEND_URL yes — app.module.ts Used for CORS / redirect validation.
BRAIN_API_PUBLIC_URL optional http://localhost:9970 .env.example Local docs; clients consume the Railway URL in non-dev.
Var Required Default Purpose
S3_BUCKET_NAME yes — Tenderloin bucket (R2) for media.
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY yes — R2 credentials.
AWS_S3_APIREGION yes auto R2 region.
AWS_S3_APIURL yes — R2 endpoint (e.g. https://<accountid>.r2.cloudflarestorage.com).
BRAIN_PUBLIC_BUCKET_URL yes — Public CDN domain for downloads.
Var Required Default Purpose
ROUND_HOST yes round:8080 gRPC target for round (embeddings, face).
BRAIN_ROUND_HOST dev round:8080 Mapped onto ROUND_HOST.
BRAIN_SIRLOIN_JOBS_SHADOW_ENABLED no false FOXY-1038 PoC: shadow-enqueue media completions into Sirloin’s job queue via jobs.v1.JobService (same host/token as the character-control dial-back). Fire-and-forget beside the webhook; off by default, operators choose where to enable it.

All optional individually but at least the providers used by enabled flows must be set.

Var Provider
BRAIN_RUNPOD_TOKEN RunPod inference.
BRAIN_FAL_AI_KEY Fal inference.
BRAIN_FAL_ADMIN_KEY Fal workspace usage and spend synchronization.
BRAIN_SPEND_SYNC_LOOKBACK_DAYS Number of previous UTC days synchronized with the current day. Defaults to 7.
BRAIN_GOOGLE_AI_API_KEY Google AI Studio.
BRAIN_GOOGLE_CLOUD_SERVICE_ACCOUNT_KEY Google Vertex AI service account JSON.
BRAIN_GOOGLE_CLOUD_PROJECT_ID, BRAIN_GOOGLE_CLOUD_LOCATION Vertex region.
BRAIN_KLING_AI_API_KEY, BRAIN_KLING_AI_API_SECRET Kling AI.
BRAIN_WAVESPEED_API_KEY Wavespeed video.
BRAIN_ATLASCLOUD_API_KEY AtlasCloud inference (Seedream, Seedance).
BRAIN_HF_TOKEN Hugging Face.
BRAIN_XAI_API_KEY xAI / Grok.
BRAIN_OPENROUTER_API_KEY OpenRouter (language extraction).

Before enabling Fal spend synchronization, confirm that BRAIN_FAL_ADMIN_KEY belongs to the production Fal workspace. Fal does not return a workspace identifier with usage data. Brain skips a window when every returned bucket is empty or zero. This guard prevents an empty-scope key from erasing history, but it cannot detect non-zero usage from the wrong workspace. It also preserves a stale non-zero value for a genuinely all-zero window until manual reconciliation.

Var Purpose
BRAIN_HIVE_CELEBRITY_RECOGNITION_API_KEY Hive celebrity check.
BRAIN_HIVE_VISUAL_MODERATION_API_KEY Hive visual moderation.
BRAIN_HIVE_DEMOGRAPHICS_API_KEY Hive demographics.
Var Purpose
BRAIN_VI_GENERATOR_URL Outbound base URL.
BRAIN_VI_GENERATOR_API_KEY API key.
BRAIN_VI_GENERATOR_CF_ACCESS_CLIENT_ID / _SECRET Cloudflare Access service token.
Var Purpose
BRAIN_GEMINI_IMAGE_SIGNATURE_KEY HMAC for signed Gemini outputs.
BRAIN_FENNEC_IMAGE_SIGNATURE_KEY HMAC for signed fennec image URLs.
Var Required Purpose
BRAIN_OTEL_URL yes (prod) Axiom OTEL endpoint.
BRAIN_OTEL_METRICS_HEADERS yes (prod) authorization=Bearer xaat-...,x-axiom-dataset=....
BRAIN_OTEL_TRACES_LOGS_HEADERS yes (prod) Same shape, traces+logs dataset.
BRAIN_OTEL_LOCAL_MOCK no Local-only: bypasses the production/staging gate and, only when BRAIN_OTEL_URL is unset, defaults the URL/headers to an in-process throwaway collector — it never overrides an explicit BRAIN_OTEL_URL. See Brain Local Development.

See Observability.

  • TODO(@pawel): Validate which of the AI provider keys are required per stage vs. lazily resolved at first use.
  • TODO(@pawel): Confirm family: 0 Redis behavior on Upstash vs. self-hosted Redis (set in apps/brain/src/config/queue.config.ts:11).