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) — except SERVER_HOST / SOCKET_HOST, which docker-entrypoint.frontend.sh writes to /config.js at container startup (runtime SERVER_HOST/SOCKET_HOST env wins, no rebuild).

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_URLyes—Prisma Postgres URLPrisma (schema.prisma env("DATABASE_URL")), run-manual-migrations.jsBoot fails; nothing works. Compose defaults to bundled postgres; set DATABASE_URL to your own DB and leave postgres out of the up service list to skip it (nothing depends on it)
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
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETyes (Google OAuth)—OAuth client pairmodules/oauth/*, modules/vault/vault.service.js/oauth/google/* 500s
BACKEND_URLno—public 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-m3model slugPrimary model
AI_FALLBACK_MODELSno3 free models (Nemotron Ultra/Super, GLM 5.2)comma slugsTried in order
OPENROUTER_HTTP_REFERERnoBACKEND_URL → http://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_KEY———Removed: nothing in production code consumed them (GEMINI_API_KEY only in scratch/ dev scripts, which read process.env directly)

Storage / files (S3 only — AWS, MinIO, RustFS)​

KeyRequiredDefaultFormatRead by
S3_ENDPOINTyes (uploads)—URL (server-side, reachable from backend)utils/fileStorage.util.js (S3 → axios fallback for foreign URLs)
S3_REGIONnous-east-1stringSame
S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEYyes (uploads)—credentialsSame; unset = uploads throw a clear error
S3_BUCKETnojet-admin-datasource-file-uploadsbucket nameSame; tenant-assets bucket for logos is fixed in constants.STORAGE
S3_PUBLIC_BASE_URLyes (uploads)—browser-facing base URLPublic file URLs (<base>/<bucket>/<key>)
S3_FORCE_PATH_STYLEno"true""true"/"false"false for AWS virtual-hosted style
RUSTFS_ACCESS_KEY / RUSTFS_SECRET_KEYstorage profilerustfsadmincredentialsBundled rustfs service (--profile storage); must match S3_* keys

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 (backend → MCP; compose sets http://mcp-server:5001)

Docker: mcp-server service runs under --profile mcp (docker compose --profile mcp up -d), needs FIREBASE_CREDENTIALS, talks to the backend at JET_ADMIN_BACKEND_URL (default http://backend:3000 in compose). Backend degrades to AI_TOOLS_UNAVAILABLE when MCP is absent.

Drift: set in Docker but unread by backend​

warning

SEED_DATABASE is read only by docker-entrypoint.backend.sh (not Node) and POSTGRES_* only by the postgres image — both intentional. The former no-ops (JWT_ACCESS_TOKEN_SECRET, JWT_REFRESH_TOKEN_SECRET, ACCESS_TOKEN_TIMEOUT, REFRESH_TOKEN_TIMEOUT, SESSION_SECRET, RABBITMQ_URL/USER/PASS, GEMINI_API_KEY, SSL_CERT_CN, UNPOOLED_DATABASE_URL, JET_ADMIN_INTERNAL_API_KEY) were removed from compose / .env.docker / environment.js — do not re-add them. amqplib stays as a dependency: RabbitMQDataSource uses per-datasource user URLs, not env.

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

KeyRequiredDefaultFormatRead byWhat breaks if wrong
VITE_SERVER_HOST / SERVER_HOSTyesbuild default http://localhost:8090; runtime /config.js wins; final fallback window.location.originURL, no trailing slashsrc/constants.js → all src/data/apis/*.js (axios base). SERVER_HOST container env is written to /config.js by docker-entrypoint.frontend.sh (runtime, no rebuild); VITE_SERVER_HOST build arg is the baked-in fallbackEvery REST call fails
VITE_SOCKET_HOST / 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 only—URL + 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.