Skip to main content

Configuration Reference

Source of truth: apps/backend/environment.js (sole sanctioned process.env reader), apps/frontend/src/{constants.js,config/*}, apps/mcp-server/environment.js, packages/mcp-server/src/{config.js,index.js}, and the docker-compose*.yml environment sections. Where compose/.env.docker and code disagree, code wins and the drift is flagged.

All backend changes require process restart. All VITE_* changes require frontend rebuild (vite build statically replaces them at build time). docker-entrypoint.frontend.sh only starts nginx — there is no runtime config override.

Backend (apps/backend, read via environment.js)

Core

KeyRequiredDefaultFormatRead byWhat breaks if wrong
NODE_ENVnodevelopmentdevelopment/production/testeverything (NODE_ID derivation, logging)test enables authProviderTest bypass — never set in prod
NODE_IDnodev_node_1 / prod_node_1stringwinston.config.js (log filename logs/<NODE_ID>-<date>.log)Log files collide across nodes if duplicated
PORTno8090inthttp-server.config.jsCompose sets 3000; Render injects $PORT. Healthchecks must target the effective port
DATABASE_URLyesPrisma Postgres URLPrisma (schema.prisma env("DATABASE_URL")), run-manual-migrations.jsBoot fails; nothing works
UNPOOLED_DATABASE_URLnodirect Postgres URLscripts requiring non-pooled connectionPool timeouts under migration load if unset (uses pooled)
ENABLED_MODULESnoauth,tenant onlycomma list, no spacesconfig/module.config.js isModuleEnabled() (missing key = enabled)Compose enables 16 modules; minimal default disables datasource/query/workflow/widget — most UI 404s
EXPRESS_REQUEST_SIZE_LIMITno5mbbytes string (5mb, 10mb)express-app.config.js (json+urlencoded)Large bundle imports rejected; uploads use separate 10 MB multer cap
CORS_WHITELISTnohttp://localhost:3000,5173,3001,127.0.0.1:3000,3001comma URLsexpress-app.config.js, socket.io.jsBrowsers blocked; /webhooks stays open (origin:true) regardless

Auth / secrets

KeyRequiredDefaultFormatRead byWhat breaks if wrong
FIREBASE_CREDENTIALSyes (any user auth)JSON service-account blobconfig/firebase.config.js (verifyIdToken)All Bearer logins fail
VAULT_ENCRYPTION_KEYyes (vault/OAuth/datasources)32-byte hexutils/encryption.util.js (AES-256-GCM)Decrypt throws; datasource tests, OAuth callback, AI tools fail. No auto-rotation
OAUTH_STATE_SECRETyes (Google OAuth)JWT secretmodules/oauth/oauth.controller.js (10-min state)OAuth handshake fails signature check
JET_ADMIN_INTERNAL_API_KEYyes (AI tools → backend)opaque stringmodules/ai/*Agent tool calls rejected
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETyes (Google OAuth)OAuth client pairmodules/oauth/*/oauth/google/* 500s
BACKEND_URLnopublic backend URLOAuth callback + OPENROUTER_HTTP_REFERER fallbackOAuth redirect + OpenRouter referer header wrong behind proxies

AI (Jet Agent, OpenRouter-compatible)

KeyRequiredDefaultFormatNotes
OPENROUTER_API_KEYyes (agent)sk-or-…Workspace fallback; tenant vault ai_config wins when set
AI_BASE_URLnohttps://openrouter.ai/api/v1URLOpenAI-compatible endpoint
AI_MODELnominimax/minimax-m3:freemodel slugPrimary model
AI_FALLBACK_MODELSno3 free models (Nemotron Ultra/Super, GLM 5.2)comma slugsTried in order
OPENROUTER_HTTP_REFERERnoBACKEND_URLhttp://localhost:8090URLRequired by OpenRouter rankings
OPENROUTER_APP_TITLEnoJet AdminstringOpenRouter dashboard label
AI_MAX_STEPSno25intAgent tool-call ceiling
AI_TEMPERATUREno0.2floatGeneration temperature
GEMINI_API_KEY / NVIDIA_API_KEYnoprovider keysLegacy/alternate providers; GEMINI_API_KEY also in compose + scratch scripts

Storage / files

KeyRequiredDefaultFormatRead by
SUPABASE_URL / SUPABASE_ANON_KEYyes (uploads)URL + JWTutils/fileStorage.util.js (S3 → Supabase-JS → axios fallback, forcePathStyle:true)
SUPABASE_S3_ENDPOINT / SUPABASE_S3_REGION / SUPABASE_S3_ACCESS_KEY_ID / SUPABASE_S3_SECRET_ACCESS_KEY / SUPABASE_S3_BUCKETyes (S3 path)S3 fieldsSame; missing fields fall through to next strategy

Logging

KeyRequiredDefaultFormatNotes
LOG_LEVELnoinfoerror/warn/success/infoFile + console level
LOG_RETENTIONno7days (int)DailyRotateFile maxFiles
LOG_FILE_SIZEno1MB (m suffix added)maxSize per file
SYSLOG_HOST / SYSLOG_PORT / SYSLOG_PROTOCOL / SYSLOG_LEVELno127.0.0.1/514/udp4/warninghost/int/proto/levelwinston-syslog transport; unreachable host only drops syslog, not files

Workflow engine (native + Temporal strangler)

KeyRequiredDefaultFormatNotes
WORKFLOW_ENGINE_DRIVER (WORKFLOW_ENGINE alias)nonativenative/temporalSelects execution path
TEMPORAL_ADDRESSTemporal onlylocalhost:7233host:portServer endpoint
TEMPORAL_NAMESPACEnodefaultstringNamespace
TEMPORAL_TASK_QUEUEnojet-admin-workflowsstringQueue (temporal/config.js also reads process.env directly)
TEMPORAL_API_KEYCloud onlynullstringCloud auth (read directly in temporal/client.js)
TEMPORAL_TLSCloud/mTLS only'false''true'/'false' stringEnables TLS block
TEMPORAL_TLS_CERT / TEMPORAL_TLS_KEY / TEMPORAL_TLS_CA / TEMPORAL_TLS_SERVER_NAMEmTLS onlynullfile paths (fs.readFileSync)Paths, not PEM literals
TEMPORAL_MAX_CONCURRENT_ACTIVITIES / TEMPORAL_MAX_CONCURRENT_WORKFLOWSno20/20intWorker parallelism
TEMPORAL_WORKER_START_MAX_ATTEMPTSno0 (= infinite)intWorker boot retries
TEMPORAL_WORKER_START_BASE_DELAY_MS / TEMPORAL_WORKER_START_MAX_DELAY_MSno1000/30000int msBackoff window
TEMPORAL_WORKER_RESTART_ON_CRASHno'true'string boolSupervisor restart
WORKFLOW_STALE_AFTER_MSno300000 (5 min)int msRUNNING instances older than this are marked FAILED at boot
TEMPORAL_HUMAN_TIMEOUTno24 hoursdurationRead directly in temporal/config.js; missing from environment.js
TEMPORAL_WORKFLOW_TYPEnodslInterpreterWorkflowstringSame direct-read gap as above

MCP bridge

KeyRequiredDefaultFormatNotes
MCP_SERVER_PORTno5001intStandalone apps/mcp-server listen port
MCP_SERVER_URLnohttp://localhost:<MCP_SERVER_PORT>URLAdvertised URL

Drift: set in Docker but unread by backend

warning

These keys appear in docker-compose.yml / .env.docker but have zero consumers in apps/backend (environment.js + process.env grep). They are currently no-ops; do not rely on them: JWT_ACCESS_TOKEN_SECRET, JWT_REFRESH_TOKEN_SECRET, ACCESS_TOKEN_TIMEOUT, REFRESH_TOKEN_TIMEOUT, SESSION_SECRET, RABBITMQ_URL, RABBITMQ_USER, RABBITMQ_PASS, SEED_DATABASE (read only by docker-entrypoint.backend.sh, not Node), POSTGRES_* (postgres image only), SSL_CERT_CN.

Frontend (apps/frontend, import.meta.env)

KeyRequiredDefaultFormatRead byWhat breaks if wrong
VITE_SERVER_HOSTyesdev http://localhost:8090, prod https://jet-admin-1.onrender.comURL, no trailing slashsrc/constants.js → all src/data/apis/*.js (axios base)Every REST call fails
VITE_SOCKET_HOSTyessame as aboveURLexecutionStreamService.js, useSocketStore.jsNo realtime (workflows, listeners, widgets)
VITE_FIREBASE_API_KEY / VITE_FIREBASE_AUTH_DOMAIN / VITE_FIREBASE_PROJECT_ID / VITE_FIREBASE_STORAGE_BUCKET / VITE_FIREBASE_MESSAGING_SENDER_ID / VITE_FIREBASE_APP_ID / VITE_FIREBASE_MEASUREMENT_IDyesnone (hard fail)Firebase web configsrc/config/firebase.jsinitializeApp throws; blank app
VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEYuploads onlyURL + anon JWTsrc/config/supabase.jsStorage features fail. Compose passes VITE_SUPABASE_KEY (no _ANON) — mismatch, ignored by code
VITE_WEBHOOK_PORTno8095intrealtimeListenerGuidanceBox.jsx (display only)Test-URL hint shows wrong port; ingestion unaffected
VITE_USE_CRAFT_EDITORnotrue (in .env)true/falseCraft.js page editor switchWrong editor variant renders

Stale README names VITE_API_URL / VITE_FIREBASE_CONFIG — neither exists in code.

MCP servers

Standalone apps/mcp-server/environment.js: PORT (default 5001), JET_ADMIN_BACKEND_URL (required), FIREBASE_CREDENTIALS (required), DEBUG. Package packages/mcp-server/src/config.js: JET_ADMIN_BACKEND_URL (falls back to JET_ADMIN_BASE_URL), JET_ADMIN_FRONTEND_URL, JET_ADMIN_TIMEOUT, JET_ADMIN_RETRIES, JET_ADMIN_RETRY_DELAY, DEBUG; src/index.js requires JET_ADMIN_API_KEY + JET_ADMIN_TENANT_ID per invocation.