Environment Variables
On this page
Note. This page is generated from the managed-services build’s sample configuration. The open-source build differs in four ways: it has no
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,AUTH_MODE,AUTH_ALB_PLATFORM_ADMIN_GROUP,REMOVE_AUTHORIZATION_FILTER_FOR_TESTING,LOG_LEVEL_TAG_PREFIX,POSTGRES_CONNECT_RETRIESorPOSTGRES_CONNECT_RETRY_DELAY_MS; its sample database name and user arepolyant; its sample also lists the admin panel’sNEXT_PUBLIC_API_URLandINTERNAL_ENGINE_URL, described in Deployment; and the settings this page places under Admin Console → Installation policies are under Settings → General.
Many product settings are no longer environment variables. The variables that used to carry them are listed under Retired variables with the place each value is set now.
Database
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | - | - |
POSTGRES_HOST | localhost | Individual PostgreSQL settings are an alternative to DATABASE_URL. The defaults match the local Docker setup. Replace POSTGRES_PASSWORD before deploying. |
POSTGRES_PORT | 5432 | - |
POSTGRES_DB | polyant_enterprise | - |
POSTGRES_USER | polyant_enterprise | - |
POSTGRES_PASSWORD | local-development-password | - |
POSTGRES_SSL | - | Set to “true” only when the DB enforces TLS (e.g. AWS Aurora). Leave empty or unset for local Docker PostgreSQL. The only accepted values are “true” and “false” (empty = unset = off); anything else - “1”, “yes”, “require”, “TRUE” - fails validation at boot rather than silently meaning OFF. UPGRADING: this used to accept any string and treat everything but the literal “true” as off. If you carry POSTGRES_SSL=1 (or “require”) against Aurora, TLS was OFF and the value is now rejected - set it to “true”. See docs/UPGRADING.md. CAVEAT: “true” gives TLS WITHOUT certificate verification - the client passes rejectUnauthorized: false (see database/client.ts), so it defeats a passive listener but not an active MITM. Verifying the chain needs a CA bundle this configuration does not take yet. |
POSTGRES_CONNECT_RETRIES | - (example: 60) | Boot-time DB readiness gate (migrate step waits for the DB before migrating). Covers the Aurora-writer warm-up on a fresh deploy. Defaults: 60 retries × 2000ms. |
POSTGRES_CONNECT_RETRY_DELAY_MS | - (example: 2000) | - |
POSTGRES_POOL_MAX | - | Connection pools. The main pool serves the message pipeline, the API and the jobs (10 is postgres.js’s own default). Analytics and dashboard reads get a separate, smaller pool, so heavy aggregates queue among themselves instead of taking the connections a conversation turn waits for; each statement on it is capped at the timeout below (milliseconds). |
POSTGRES_ANALYTICS_POOL_MAX | - | - |
POSTGRES_ANALYTICS_STATEMENT_TIMEOUT_MS | - | - |
HTTP Server (NestJS)
| Variable | Default | Description |
|---|---|---|
API_PORT | 4000 | - |
Encryption
| Variable | Default | Description |
|---|---|---|
ENCRYPTION_KEY | - | 32-byte hex-encoded key for AES-256-GCM encryption of instance secrets. Generate with: node -e “console.log(require(‘crypto’).randomBytes(32).toString(‘hex’))“ |
Authentication
| Variable | Default | Description |
|---|---|---|
AUTH_SECRET | - | Shared secret between engine and web for JWT verification (Auth.js JWE). Must be identical in both packages. Generate with: openssl rand -hex 32 |
AUTH_TRUST_HOST | true | Auth.js host trust. Required for any self-hosted deployment - including local development on http://localhost - and when running behind a reverse proxy (Render, Railway, nginx, etc.). Leave at true unless you run on a platform (e.g. Vercel) that sets the host automatically. Used by the web package, so it must also be present in packages/web/.env.local. |
Google OAuth (web only)
| Variable | Default | Description |
|---|---|---|
GOOGLE_CLIENT_ID | - | Create credentials at https://console.cloud.google.com → APIs & Services → Credentials |
GOOGLE_CLIENT_SECRET | - | - |
AUTH_MODE | session | Auth source for the engine’s global AuthGuard. session (default) - Auth.js JWT (cookie/Bearer) + per-instance API key. session is the only value that boots. alb-oidc is REFUSED at startup (config.ts exits): a gateway-forwarded identity carries no organization and holds no role bindings, so it was denied on every management route - a mode that only worked under a condition nobody declared. Re-enabling it means mapping the gateway identity onto a local user, not deleting the check. |
AUTH_ALB_PLATFORM_ADMIN_GROUP | - (example: polyant-platform-admins) | In alb-oidc mode, members of this Cognito group receive the platform_admin role. Change this sample value to the group configured in your identity provider. |
REMOVE_AUTHORIZATION_FILTER_FOR_TESTING | - (example: true) | RBAC PermissionGuard. Always ENFORCED here: undeclared routes and failed permission checks are denied with 403. There is no variable to turn that off in production - NODE_ENV=production ignores the escape hatch below. REMOVE_AUTHORIZATION_FILTER_FOR_TESTING=true drops the guard to SHADOW mode (every would-be denial logged as [authz] shadow: would deny …, nothing denied) and works ONLY outside production. It is a local-debugging aid: with it set every @RequirePermission is a no-op and cross-organization isolation is off, so any authenticated user reaches the whole management plane. NOTE: this deployment does NOT read AUTHZ_ENFORCE - that is the OSS knob for the same posture. Setting it here does nothing, which has already sent someone down the wrong path while diagnosing a 403. |
CORS_ORIGINS | - | Comma-separated list of origins allowed to call the engine API (CORS). Leave empty in development if engine and web run on the same origin (rewrites). In production, set this to the public origin of your web app. Example: CORS_ORIGINS=https://app.example.com,https://admin.example.com A credentialed wildcard (*) is refused at startup - list explicit origins. |
Reverse proxy
| Variable | Default | Description |
|---|---|---|
TRUST_PROXY | 0 | Number of trusted proxy hops between the engine and the public internet (e.g. set to 1 if a single reverse proxy like Render/Railway/nginx sits in front of the engine). Controls whether X-Forwarded-Host / X-Forwarded-Proto headers are honored when reconstructing the request URL for the Twilio webhook signature check. Accepts an integer hop count or true/false. Leave at 0 (default) if the engine is exposed directly - otherwise attackers could spoof Host/Proto and bypass the Twilio HMAC. It also decides the client address rate limiting sees: behind a proxy left at 0, every request comes from the proxy’s address and shares its limits. For the URL, it matters for a WhatsApp channel in authToken mode, whose inbound authentication is the Twilio HMAC over the reconstructed URL. A channel in apiKey mode is gated by a secret in the webhook path, which no forwarded header can influence. |
API rate limiting (@nestjs/throttler)
| Variable | Default | Description |
|---|---|---|
THROTTLE_ENABLED | - (example: false) | Per-IP throttling on the HTTP API, and the only part of it that is a variable: whether it runs at all. Only the literal false disables ALL throttling - the global default and every per-route @Throttle override - which is what parallel dev/eval runs firing from one IP want. Default on. The WINDOW and the LIMIT are platform policies, edited at Admin Console → Installation policies, so a limit that turns out to be too tight is a form rather than a redeploy. They are not here on purpose: a rate limiter that could be turned off from inside the product is no use to a locked-out administrator. |
Web → Engine URL
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | http://localhost:4000 | URL the Next.js frontend uses to reach the engine API (server-side rewrites). |
INTERNAL_ENGINE_URL | http://localhost:4000 | Internal URL the web’s Credentials provider uses to call the engine’s /api/auth/credentials/verify endpoint (server-side only). Defaults to http://localhost:4000 . In production, point this at the engine’s internal address (e.g. http://engine:4000 inside a private network). |
Auth
| Variable | Default | Description |
|---|---|---|
AUTH_INTERNAL_SECRET | - (example: replace-with-a-generated-credentials-secret) | Shared secret used by the web’s Credentials provider to call the engine’s /api/auth/credentials/verify endpoint. Must be identical in engine and web .env files. Leave this optional setting unset to disable email/password login. Generate with: node -e “console.log(require(‘crypto’).randomBytes(48).toString(‘base64url’))“ |
INITIAL_ADMIN_EMAIL | - (example: [email protected]) | Initial admin user - created on first boot if the users table is empty. INITIAL_ADMIN_PASSWORD is REQUIRED to seed the admin: if unset, seeding is skipped (no auto-generation) to avoid writing the secret to the engine logs. INITIAL_ADMIN_EMAIL is optional (defaults to administrator@local); set on a non-empty database it also creates or unlocks that account as platform admin. |
INITIAL_ADMIN_PASSWORD | - (example: choose-a-strong-password) | - |
External plugins
| Variable | Default | Description |
|---|---|---|
PLUGIN_DIRS | - | Comma-separated absolute paths scanned for external plugins in addition to the built-in plugin directory. Leave empty unless self-hosting and loading a local plugin. Example: /opt/polyant/plugins,/srv/acme-plugin |
PLUGIN_MARKETPLACE_OFFICIAL_ENABLED | - (example: true) | Plugin marketplaces. The official Exelab marketplace is on by default and its signing keys ship with the engine; set these only to point a deployment at a different official origin, rotate keys ahead of a release, or switch it off. Other marketplaces (signed or not) are added at runtime by a Platform Admin in Platform → Plugins. Every origin must use HTTPS. |
PLUGIN_MARKETPLACE_ORIGIN | - (example: https://marketplace.polyant.ai) | - |
PLUGIN_MARKETPLACE_TRUSTED_KEYS_JSON | - (example: [{"keyId":"exelab-2026-10","publicKey":"-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----"}]) | - |
PLUGIN_MARKETPLACE_ALLOW_LOOPBACK_HTTP | - (example: false) | Plain HTTP to a loopback host (localhost, 127.x, [::1]) for local fixtures and tests. Refused at boot when NODE_ENV=production. |
PLUGIN_MARKETPLACE_ALLOW_UNSIGNED | - (example: false) | Whether a Platform Admin may add a marketplace without signature checks. Defaults to false in production and true elsewhere; an existing unsigned marketplace is not read while this is false. |
PLUGIN_MATERIALIZATION_ROOT | - (example: /tmp/polyant-plugins) | Downloaded bundles are verified and extracted here (created owner-only); the directory is ephemeral runtime state and can be rebuilt from PostgreSQL desired state after restart. |
PLUGIN_CATALOG_POLL_MS | 300000 | - |
PLUGIN_MAX_WORKERS | 8 | - |
PLUGIN_WORKER_IDLE_MS | 300000 | - |
PLUGIN_WORKER_HEAP_MB | 128 | - |
PLUGIN_WORKER_LOAD_TIMEOUT_MS | 15000 | A plugin module that has not finished importing by then fails and its worker is terminated. |
PLUGIN_CALL_TIMEOUT_MS | 60000 | Deadline of a plugin tool call; a hook call uses the hook’s own timeout. |
PLUGIN_ABORT_GRACE_MS | 5000 | An aborted call still running after this is treated as stuck: its worker is terminated and the call counts towards the plugin’s circuit. |
PLUGIN_CIRCUIT_FAILURES | 3 | - |
PLUGIN_CIRCUIT_WINDOW_MS | 300000 | - |
PLUGIN_CIRCUIT_COOLDOWN_MS | 60000 | - |
PLUGIN_MAX_COMPRESSED_BYTES | 26214400 | - |
PLUGIN_MAX_EXPANDED_BYTES | 104857600 | - |
PLUGIN_MAX_FILES | 2000 | - |
PLUGIN_SYNC_RPC_BYTES | 1048576 | - |
Panel build (packages/web, build time)
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_APP_VERSION | - | Next reads .env only from packages/web/, never this file: these belong in packages/web/.env.local (or the build environment), and they are baked into the bundle at build time - changing one needs a rebuild, not a restart. - NEXT_PUBLIC_APP_VERSION: version shown in the panel’s About. Defaults to the version in packages/web/package.json. - NEXT_PUBLIC_APP_REVISION: commit shown beside it. Falls back to GITHUB_SHA (set by GitHub Actions), then to empty. Dockerfile.web takes it as a build argument. |
NEXT_PUBLIC_APP_REVISION | - | - |
Logging verbosity
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | info | Controls how much the structured/pipeline loggers emit (console + daily log files at logs/engine-YYYY-MM-DD.log under the Polyant project root, or /app/logs/engine-YYYY-MM-DD.log in Docker). One of: debug | info | warn | error | silent. Default: info. - debug: verbose per-step pipeline tracing (LLM call lines, tool-call args, system-prompt length, context load) on top of info - info: high-value skeleton - request, LLM token/latency, tool results, supervisor + response timing - warn: suppress info-level lines, keep warnings + errors - error: errors only - silent: disable all structured logging Note: the full system prompt is never logged here. Full-payload inspection is the per-instance debug_enabled flag, which persists the prompt, the messages and the tool definitions for analysis instead of dumping them to stdout. |
LOG_LEVEL_TAG_PREFIX | - (example: EXELAB) | Prefix on the level tag every log record carries ( |
VOICE_DEBUG_TIMELINE | - (example: true) | Telephone voice channel: every call’s timeline event and per-turn line in the log (names, timings and counts, never words), for following a call step by step. Call start/end, failures and refusals are logged without it. |
VOICE_SHUTDOWN_DRAIN_MS | - (example: 15000) | On shutdown, how long phone calls in progress may continue before they are ended (milliseconds, 0-110000, default 15000); new calls are refused meanwhile. Keep it plus the 10 s HTTP grace period under the container’s stop timeout. |
Base URL
| Variable | Default | Description |
|---|---|---|
BASE_URL | http://localhost:4000 | Public base URL of the engine: the origin an external service must use to reach it, and what every webhook URL, OAuth redirect and agent card is built from. This is the BOOTSTRAP value. A platform admin can set the public address at Admin Console → Installation policies and that wins, which is how a wrong address is corrected without a redeploy. It cannot be derived from the incoming request: the panel reaches the engine through its own rewrite, so the host on that request is the internal one, and an OAuth redirect URI that varied per request would never match the one registered with the provider. |
Retired variables and where they are set now
The engine no longer reads these. A deployment that still sets one keeps booting, the engine logs a warning at boot naming where the value is set now, and the value has no effect. Before removing a variable you had set to something other than its default, enter the same value in its new place. See Upgrading.
| Variable | Where the value is set now |
|---|---|
DATETIME_TIMEZONE, DATETIME_LOCALE | The agent’s Advanced → Behaviour overrides. A deployment-wide time zone is TZ. |
DEDUP_SIMILARITY_THRESHOLD | The agent’s Advanced → Behaviour overrides (Memory dedup threshold, default 0.90). |
MESSAGE_SOFT_DEBOUNCE_MS, MESSAGE_TYPING_DELAY_MS, MESSAGE_MAX_RESTARTS | The agent’s Advanced → Behaviour overrides (defaults 2000 ms, 1500 ms and 3). |
KNOWLEDGE_MAX_DOCS_PER_INSTANCE | The organization’s knowledge-document cap, default 500 per agent. The managed-services build sets it in the database column organizations.knowledge_max_docs_per_agent; there is no console field yet. |
ANALYTICS_RETENTION_DAYS, SSE_MAX_CONNECTIONS, SSE_MAX_CONNECTIONS_PER_USER, THROTTLE_TTL_MS, THROTTLE_LIMIT, AGENT_CALL_TIMEOUT_MS, MCP_CONNECT_TIMEOUT_MS, SCHEDULER_ORPHAN_GRACE_MS, SCHEDULER_DEFAULT_MAX_RUN_MS | Installation policies, with the same defaults. THROTTLE_ENABLED stays an environment variable. |
CONVERSATION_LIST_TIMEOUT_MS | Installation policies (managed services). |
SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASSWORD, MAIL_FROM, PANEL_URL | The mailer in Installation policies (managed services). The old values are not read as a fallback. |
AUTH_ALLOWED_DOMAIN, AUTH_ALLOWED_DOMAINS | Each organization’s SSO domains (managed services). |
DEFAULT_ORG_NAME | The organization’s name, edited in the console (managed services). |
RETENTION_DEFAULT_DAYS | Each retention policy states its own window (managed services). |
PLATFORM_S3_BUCKET, PLATFORM_S3_REGION, PLATFORM_S3_ACCESS_KEY_ID, PLATFORM_S3_SECRET_ACCESS_KEY | Each agent’s own storage secrets. See Attachment storage. |
AWS_REGION | No longer a Polyant fallback. Set the AWS region on each agent, or on its organization (managed services). The AWS SDK may still read the variable for its own purposes. |
PLATFORM_ADMIN_EMAIL | Nothing. The first platform admin is the account INITIAL_ADMIN_EMAIL names; promote others from Platform members. |
DEBUG_LLM_PAYLOAD | The agent’s own debug capture. |
LANGSMITH_API_KEY, LANGSMITH_PROJECT, LANGSMITH_TRACING | Nothing: tracing is configured per agent. |
DEFAULT_INSTANCE_ID, WORKSPACES_ROOT | Nothing. |
PDF_CONCURRENCY | The Markdown-to-PDF plugin’s own configuration. |