PopChoice Docs

Environment Reference

Canonical reference for PopChoice environment variables across local development, CI, deployment, services, and observability.

This page is the canonical environment-variable reference for PopChoice. It supports the documentation backlog in #515 and implements #516.

The root .env is the local source of truth. After changing it, run npm run copy:env so apps/web, packages/shared, and services receive the same values. For setup steps see Setup, Coolify, Services, CI/CD, Observability Metrics, and Observability Traces.

Never commit plaintext secrets. Keep .env files, API keys, database passwords, Redis credentials, session secrets, HMAC secrets, Resend tokens, Telegram bot tokens, and Grafana passwords in a local secret store or deployment secret manager. NEXT_PUBLIC_* values and build metadata are public by design.

Runtime App

These variables are used by apps/web, workers, Bull Board, and shared runtime helpers.

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
OPENAI_API_KEYWeb, workers, seed/discovery/backfillRequired for realistic local/prod recommendations and embeddings; not required for deterministic CI evals/e2eNoneSecret. Used for embeddings and recommendation text generation.
DATABASE_URLWeb, workers, services, migrations, backofficeRequired for app DB behavior; CI/e2e may use E2E_DATABASE_URL insteadLocal setup generates itSecret if it contains credentials. PostgreSQL must support pgvector.
REDIS_URLWeb, workers, BullMQ, Bull Board, rate limitingOptional local; required for queued recommendation flow in prod; e2e maps from E2E_REDIS_URLQueue features disable or use limited inline fallback when missingSecret if it contains credentials. Backoffice only needs it for future queue state screens.
TMDB_API_KEYWeb, workers, servicesOptional for local UI; required for TMDB enrichment, discovery, backfill, more picks, and production catalog freshnessNoneSecret. Must be a TMDB v4 read access token for service/backfill flows.
NEXT_PUBLIC_TMDB_API_KEYBrowserOptionalNonePublic. Enables client-side poster enrichment only; do not put privileged secrets here.
NEXT_PUBLIC_BASE_URLWeb, auth, password reset, build infoOptional local; required behind reverse proxy/prodFalls back to request origin or platform domain where supportedPublic. Use the browser-facing origin without a trailing slash.
LOG_LEVELWeb, workers, Bull Board, shared loggerOptional everywhereinfoUse debug, info, warn, or error.
NODE_ENVNext.js, auth, metrics, tracingSet by framework/Docker/CIdevelopment locally, production in imagesControls production auth strictness, secure cookies, and default metrics/tracing behavior.
HOSTNAMEWeb container, tracingSet by Docker/CoolifyContainer hostnameUsed as OpenTelemetry service.instance.id; web binds to 0.0.0.0 in Compose.
PORTWeb, Bull Board, backoffice, Storybook devOptionalWeb/backoffice 3000; Bull Board 4000 or script-specific defaultIn Coolify the public proxy usually routes to container port 3000; static Storybook uses nginx port 80.
BULL_BOARD_PORTBull Board scriptsOptional local4000 in apps/bull-board, 3001 in app-local scriptPrefer PORT in container deployments.
OPERATOR_AUTH_USERNAMEBull Board, backofficeOptional local; required for protected production operator surfacesNoneBasic Auth username for operational/admin UIs.
OPERATOR_AUTH_PASSWORDBull Board, backofficeOptional local; required for protected production operator surfacesNoneSecret. Set with OPERATOR_AUTH_USERNAME; rotate like an admin password.
OPERATOR_AUTH_REALMBull Board, backofficeOptionalPopChoice OperatorsBrowser login prompt realm.
OPERATOR_AUTH_REQUIREDBull Board, backofficeOptionalfalseSet 1 to fail startup when operator credentials are missing.
OPERATOR_AUTH_RATE_LIMIT_MAXBull Board, backofficeOptional30Maximum unsuccessful operator-surface requests per window. Successful requests are skipped.
OPERATOR_AUTH_RATE_LIMIT_WINDOW_SECONDSBull Board, backofficeOptional900Operator-surface auth rate-limit window in seconds.

Auth And Email

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
AUTH_SESSION_SECRETWeb auth/sessionOptional local; required in production when login is enabledFalls back to API_KEY_HMAC_SECRET, then ephemeral dev secret outside productionSecret. Must stay stable across restarts or sessions/password-reset tokens break.
API_KEY_HMAC_SECRETAPI auth, password reset fallbackRequired when VALID_API_KEYS is set; recommended prodNoneSecret. Used to derive and verify API key digests.
VALID_API_KEYSProtected API routesOptional local; required in production for API-key accessMissing in dev disables API-key auth with a warning; missing in prod rejects protected API requestsSecret-ish digest list. Store scrypt digests, never plaintext API keys.
RESEND_API_KEYPassword reset emailOptional local; required for production email deliveryLocal/dev can expose reset URL without sending emailSecret.
EMAIL_FROMPassword reset emailRequired with RESEND_API_KEY in productionNonePublic sender identity, but keep deployment config consistent with verified domain.
EMAIL_REPLY_TOPassword reset emailOptionalNonePublic support/reply-to address.

Local Database And Migrations

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
POSTGRES_USERLocal Docker, Coolify PostgresGenerated locally; optional prodpopchoice in CoolifySecret only if reused as credential metadata.
POSTGRES_PASSWORDLocal Docker, Coolify PostgresGenerated locally; required prodNoneSecret. Required before first Coolify deploy because PostgreSQL initializes with it.
POSTGRES_DBLocal Docker, Coolify PostgresGenerated locally; optional prodpopchoice in CoolifyUsually non-secret.
DB_MIGRATION_CONNECT_ATTEMPTSapps/web/scripts/migrate-db.js, e2e setupOptional20; e2e setup uses 30Increase when DB startup is slow.
DB_MIGRATION_CONNECT_DELAY_MSDB migration script, e2e setupOptional3000; e2e setup uses 1000Delay between migration connection attempts.

Workers And Catalog Services

These tune BullMQ workers and the standalone catalog services described in Services.

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
WORKER_METRICS_PORTWorker metrics serverOptional9464Exposes /metrics from the worker process.
CATALOG_MAINTENANCE_CONCURRENCYCatalog-maintenance workerOptional1Keep low when TMDB rate limits matter.
CATALOG_TMDB_REQUESTS_PER_WINDOWCatalog-maintenance workerOptional10Shared TMDB request budget.
CATALOG_TMDB_RATE_LIMIT_WINDOW_MSCatalog-maintenance workerOptional10000Window for the shared TMDB budget.
CATALOG_TMDB_429_BACKOFF_MSCatalog-maintenance workerOptional30000Backoff when TMDB returns 429 without Retry-After.
TMDB_SOURCESDiscovery service, enqueue scriptOptionalAll four TMDB sources in service; enqueue script defaults to its configured setComma-separated now_playing,upcoming,top_rated,popular.
MAX_PAGES_PER_SOURCEDiscovery service, enqueue scriptOptional3TMDB pages per source.
MIN_VOTE_COUNTDiscovery service, enqueue scriptOptional500Quality filter.
MIN_VOTE_AVERAGEDiscovery service, enqueue scriptOptional6.5Quality filter.
MAX_MOVIES_PER_RUNDiscovery serviceOptional50Discovery insert/embedding cap per run.
MAX_MOVIES_PER_PAGEDiscovery enqueue scriptOptional20Per-page enqueue cap for catalog maintenance.
MAX_MOVIESBackfill service, enqueue scriptOptional0 means all for backfill; enqueue script defaults to 100Use for bounded runs.
TMDB_LANGUAGEDiscovery/backfill/enqueue scriptsOptionalen-USTMDB locale tag such as fi-FI or ru-RU.
SYNC_SCHEDULEMovie discovery serviceOptional0 0 * * 0Cron expression in UTC; empty value means one-shot mode.
BATCH_SIZEMovie backfill serviceOptional5Parallel TMDB detail requests per batch.
MOVIES_FILE_PATHMovie seed serviceOptional<cwd>/movies.txtPath for curated seed input.
DRY_RUNSeed/discovery/backfill servicesOptionalfalseUse true to log intended changes without writes where supported.
CATALOG_HEALTH_FORMATCatalog health CLIOptionaltextUse json for machine-readable output.
CATALOG_HEALTH_SAMPLE_LIMITCatalog health CLI/backofficeOptional5Sample rows/groups per issue.
CATALOG_HEALTH_STALE_DAYSCatalog health CLI/backofficeOptional180Stale TMDB metadata threshold.

CI And E2E

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
CIGitHub Actions, Playwright, lintSet by GitHub ActionsFalse locallyChanges retries, reporters, forbidOnly, and console lint strictness.
E2E_PORTPlaywright e2eOptional local/CI3100Port for the test web server.
E2E_BASE_URLPlaywright e2eOptional local/CIhttp://127.0.0.1:${E2E_PORT}Browser base URL for e2e.
E2E_DATABASE_URLE2E setup and PlaywrightOptionalpostgresql://popchoice_e2e@127.0.0.1:55432/popchoice_e2ePoints to disposable e2e PostgreSQL.
E2E_REDIS_URLPlaywright e2eOptionalredis://127.0.0.1:56379Points to disposable e2e Redis.
E2E_SKIP_DOCKERE2E setupOptionalDocker is used unless set to 1Set to 1 when external e2e DB/Redis are already running.
E2E_DETERMINISTIC_RECOMMENDATIONSRecommendation jobs/e2eSet by Playwright configDisabled unless 1Uses deterministic fixtures instead of live AI/TMDB for product e2e.
NEXT_FONT_GOOGLE_DISABLENext.js build CISet in CI build jobNot set locallyAvoids flaky Google Fonts network access.
NEXT_TELEMETRY_DISABLEDNext.js/docs buildOptionalNot setUseful in CI and local verification.

Coolify And Container Images

Coolify uses coolify.compose.yml as the runtime source of truth. For the full deployment flow, see Coolify and CI/CD.

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
APP_IMAGE_PREFIXCoolify composeOptional prodghcr.io/shchilkin/popchoicePublic deployment metadata.
IMAGE_TAGCoolify composeRequired to pin release intentionallydevelopmentUse one tag for all PopChoice runtime images.
SERVICE_NAME_DBCoolify runtime env helperOptionaldbLets Coolify service names differ from local Compose names.
SERVICE_NAME_REDISCoolify runtime env helperOptionalredisLets Coolify service names differ from local Compose names.
COOLIFY_DEPLOY_WEBHOOKGitHub Actions secretRequired only for auto-deployNoneSecret URL. Stored in GitHub repository secrets.
COOLIFY_TOKENGitHub Actions secretRequired with deploy webhookNoneSecret API token used as Authorization: Bearer.
POPCHOICE_PRODUCTION_BASE_URLGitHub Actions secretOptional for post-deploy verificationNonePublic app origin used to poll /api/health and /api/build after auto-deploy.
GRAFANA_URLGitHub Actions secretOptional for deploy silencesNoneGrafana origin used by deploy workflow to create temporary silences.
GRAFANA_SERVICE_ACCOUNT_TOKENGitHub Actions secretOptional with GRAFANA_URLNoneSecret token with permission to create Grafana silences.
DEPLOY_SILENCE_MINUTESGitHub Actions envOptional15Duration for the deploy-sensitive alert silence window.
COOLIFY_BRANCH / COOLIFY_RESOURCE_UUIDCoolify/build metadataPlatform-provided or optionalEmptyNon-secret deployment metadata.

Build Metadata

These values are non-secret provenance fields exposed by /api/build and the browser PopChoice.info() helper. Runtime APP_* values win over baked BUILD_* Docker metadata.

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
APP_VERSION / APP_CHANNELBuild info, tracingOptionalVersion defaults to package/release value where configured; channel defaults to developmentPublic metadata.
APP_COMMIT_SHA / BUILD_APP_COMMIT_SHABuild infoOptional but recommended prodFalls back through source/GitHub/provider commit fields, then unknownPublic metadata. Must be a valid SHA to display.
SOURCE_COMMIT / BUILD_SOURCE_COMMITBuild infoOptionalEmptyPublic PR/source commit metadata.
APP_GIT_BRANCH / BUILD_APP_GIT_BRANCHBuild infoOptionalFalls back through source/Coolify/GitHub/provider branch fieldsPublic metadata.
SOURCE_BRANCH / BUILD_SOURCE_BRANCHBuild infoOptionalEmptyPublic PR/source branch metadata.
APP_PR_NUMBER / BUILD_APP_PR_NUMBERBuild infoOptionalEmptyPublic preview metadata.
APP_IMAGE_REPOSITORY / BUILD_APP_IMAGE_REPOSITORYBuild infoOptionalEmptyPublic image provenance.
APP_IMAGE_TAG / BUILD_APP_IMAGE_TAGBuild infoOptionalEmptyPublic image provenance.
APP_IMAGE_DIGEST / BUILD_APP_IMAGE_DIGESTBuild infoOptionalEmptyPublic image provenance; use digest-pinned values for releases.
GITHUB_SHA, GITHUB_REF_NAMEGitHub Actions/build infoCI-providedEmpty outside GitHub ActionsPublic metadata.
VERCEL_GIT_COMMIT_SHA, VERCEL_GIT_COMMIT_REFBuild info fallbackPlatform-provided if deployed on VercelEmptyPublic metadata; retained as portable fallback.

Metrics And Tracing

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
METRICS_ENABLEDWeb, workersEnabled by default in development; disabled by default in productionNODE_ENV !== productionSet true in production only with access controls/token.
METRICS_BEARER_TOKENWeb metrics, PrometheusRequired for protected production scrapingDev allows metrics without token unless disabledSecret. Must match app stack and observability stack.
TRACING_ENABLEDWeb, workersOptionalDisabled unless truthy or OTLP endpoint existsEnables OpenTelemetry SDK startup.
TRACING_SAMPLE_RATEWeb, workersOptional0.05 prod, 1 devKeep prod sampling conservative.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTWeb, workersOptionalCoolify app defaults to http://observability-otel-collector:4318/v1/tracesPreferred trace endpoint variable.
OTEL_EXPORTER_OTLP_ENDPOINTWeb, workersOptionalUsed to derive /v1/traces when trace endpoint is absentGeneric OTLP base endpoint fallback.
OTEL_SERVICE_NAMEWeb, workersOptionalpopchoice-web or popchoice-workersOverride only when splitting services further.
OTEL_DIAG_LOG_LEVELWeb, workersOptionalNoneerror, warn, info, debug, verbose, or none.
OTEL_TRACES_SAMPLER_ARGWeb, workersOptionalUsed if TRACING_SAMPLE_RATE is absentOpenTelemetry-compatible sampler arg fallback.

Observability Stack

These belong to docker-compose.observability.yml, not the main app compose resource.

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
OBSERVABILITY_IMAGE_TAGObservability config imagesOptionallocalImage tag for local/Coolify-built observability config images.
POPCHOICE_APP_NETWORKObservability stackRequired when app network is not popchoice_defaultpopchoice_defaultMust match the Docker network where web, workers, db, and redis are reachable.
POPCHOICE_WEB_METRICS_TARGETPrometheusOptionalweb:3000Host:port for web metrics target.
POPCHOICE_WORKERS_METRICS_TARGETPrometheusOptionalworkers:9464Host:port for worker metrics target.
POSTGRES_EXPORTER_DATA_SOURCE_URIPostgres exporterOptionaldb:5432/popchoice?sslmode=disableUse app DB service name/database.
POSTGRES_EXPORTER_DATA_SOURCE_USERPostgres exporterOptionalpopchoiceDB user for exporter.
POSTGRES_EXPORTER_DATA_SOURCE_PASSPostgres exporterRequired when DB password is setEmptySecret. Copy from app DB password; observability resource does not inherit it.
REDIS_EXPORTER_REDIS_ADDRRedis exporterOptionalredis://redis:6379Include credentials if Redis is protected.
GRAFANA_ADMIN_USERGrafanaOptionaladminAdmin username.
GRAFANA_ADMIN_PASSWORDGrafanaRequired for observability stack startupNoneSecret.
GRAFANA_TELEGRAM_BOT_TOKENGrafana alertingOptionalMissing value skips Telegram contact provisioningSecret.
GRAFANA_TELEGRAM_CHAT_IDGrafana alertingOptionalMissing value skips Telegram contact provisioningPrivate destination id.
GF_SERVER_ROOT_URLGrafanaOptionalhttp://localhost:3000Set to public Grafana URL so alert links are useful outside Docker.

Docs App

The Fumadocs app reads markdown/MDX from docs/ and does not require application secrets. Use:

VariableOwner / serviceLocal / prod / CIDefault / fallbackNotes
PORTapps/docs production serverOptional3003 for dev script; Next.js default for next start unless overriddenUse deployment platform routing for public docs.
NEXT_TELEMETRY_DISABLEDDocs build/devOptionalNot setSafe to set to 1 in CI.

On this page