Environment Variables
Full reference of every supported environment variable, grouped by category.
Client variable prefix by app
Section titled “Client variable prefix by app”Browser-exposed variables are build-time inlined. The prefix depends on which app you run:
| App | Client prefix | Example |
|---|---|---|
apps/dashboard (TanStack Start, current) | VITE_* | VITE_AUTH_PROVIDER |
| Legacy Next.js (v0.2 and earlier) | NEXT_PUBLIC_* | NEXT_PUBLIC_AUTH_PROVIDER |
The tables below use VITE_*. If you are migrating from v0.2, substitute NEXT_PUBLIC_ wherever you see VITE_. Server-side variables (CLICKHOUSE_*, CHM_*, LLM_*, CLERK_SECRET_KEY, etc.) are the same.
Authoritative example: apps/dashboard/.env.example.
Build-time vs runtime
Section titled “Build-time vs runtime”There are two categories of environment variables:
| Category | When resolved | How to set | Example |
|---|---|---|---|
| Build-time | When bun run build runs | CI environment / shell before the build | VITE_FEATURE_CONVERSATION_DB, VITE_AUTH_PROVIDER, VITE_CLERK_PUBLISHABLE_KEY |
| Runtime | When the server process starts per request | wrangler.toml [vars], wrangler secret put, Docker -e, k8s ConfigMap/Secret | CLICKHOUSE_HOST, CONVERSATION_STORE_BACKEND |
VITE_* vars are always build-time. They are inlined into the browser bundle and cannot be changed without a rebuild. Setting a VITE_* var in wrangler.toml [vars] or as a Docker -e flag has no effect on the running app — the bundle already has the value from when it was built.
All other vars (unless noted) are runtime — read from process.env when the Worker or Node process handles a request.
ClickHouse Connection
Section titled “ClickHouse Connection”Required. Set at least CLICKHOUSE_HOST.
| Variable | Default | Description |
|---|---|---|
CLICKHOUSE_HOST | — (required) | Comma-separated ClickHouse host URLs, e.g. http://ch-1:8123,http://ch-2:8123. |
CLICKHOUSE_USER | default | Comma-separated usernames, one per host. |
CLICKHOUSE_PASSWORD | "" | Comma-separated passwords, one per host. |
CLICKHOUSE_NAME | — | Comma-separated display labels shown in the host selector. |
CLICKHOUSE_HOST defines the host count. CLICKHOUSE_USER and CLICKHOUSE_PASSWORD may be either a single value (applied to all hosts) or one value per host position. CLICKHOUSE_NAME is optional. Position N maps to host index N.
See Multiple Hosts and Custom Name.
Query Execution
Section titled “Query Execution”| Variable | Default | Description |
|---|---|---|
CLICKHOUSE_MAX_EXECUTION_TIME | 60 | Query timeout in seconds. |
CLICKHOUSE_TZ | server default | Time zone for date/time display. |
CLICKHOUSE_DATABASE | system | Database used for app-owned tables (self-tracking events, dashboards). |
EVENTS_TABLE_NAME | system.monitoring_events | Full table name override for self-tracking events. |
Connection Pool
Section titled “Connection Pool”| Variable | Default | Description |
|---|---|---|
CLICKHOUSE_POOL_SIZE | 10 | Max concurrent ClickHouse clients per host. |
CLICKHOUSE_POOL_TIMEOUT | 300000 | Idle client timeout in milliseconds (5 min). |
CLICKHOUSE_POOL_CLEANUP_INTERVAL | 60000 | Stale-client cleanup interval in milliseconds (1 min). |
Health Alerting
Section titled “Health Alerting”The cron sweep (GET /api/cron/health-sweep, Cloudflare Cron Trigger every 5 minutes) runs health checks over all hosts and can post webhook alerts without a browser tab open. See Environment Variables — Health Alerting in context.
| Variable | Default | Description |
|---|---|---|
CRON_SECRET | — | Shared secret guarding /api/cron/health-sweep. Send as Authorization: Bearer <secret>. When unset, the endpoint is open. |
HEALTH_ALERT_ENABLED | false | Set true to POST webhook alerts. Checks run regardless; alerts only fire when true. |
HEALTH_ALERT_WEBHOOK_URL | — | Slack- or Discord-compatible webhook URL. Required for alerts to be dispatched. |
HEALTH_ALERT_MIN_SEVERITY | warning | Minimum severity to alert: warning (warning + critical) or critical (critical only). |
## Alert Slack on warning-or-worseCRON_SECRET=a-long-random-stringHEALTH_ALERT_ENABLED=trueHEALTH_ALERT_WEBHOOK_URL=https://hooks.slack.com/services/T000/B000/XXXXHEALTH_ALERT_MIN_SEVERITY=warningFeature Permissions
Section titled “Feature Permissions”All features are public and enabled by default. Override only what needs different behavior.
| Variable | Default | Description |
|---|---|---|
CHM_CONFIG_FILE | — | Path to TOML or YAML config file for feature overrides. |
CHM_DISABLED_FEATURES | — | Comma-separated feature ids to disable entirely. |
CHM_AUTH_REQUIRED_FEATURES | — | Comma-separated feature ids that require authentication. |
CHM_FEATURE_{ID}_ACCESS | public | Per-feature access: public, guest (alias for public), or authenticated. |
CHM_FEATURE_{ID}_ENABLED | true | Per-feature enabled flag: true or false. |
Replace {ID} with an uppercase feature id: OVERVIEW, AGENT, INSIGHTS, HEALTH, QUERIES, TABLES, METRICS, DASHBOARD, SECURITY, LOGS, SETTINGS, CLUSTER, OPERATIONS, ACTIONS, MCP, DOCS, ABOUT, PEERDB.
CHM_FEATURE_AGENT_ACCESS=authenticatedCHM_FEATURE_METRICS_ENABLED=falseCHM_DISABLED_FEATURES=settings,insightsSee Feature Permissions for config-file examples and precedence details.
Authentication
Section titled “Authentication”The active server-side auth provider is set by CHM_AUTH_PROVIDER. See Authentication for the full model.
| Variable | Default | Description |
|---|---|---|
CHM_AUTH_PROVIDER | none | Server auth provider: none, clerk, proxy, or trusted. |
VITE_AUTH_PROVIDER | none | Client-side mirror of CHM_AUTH_PROVIDER. Set to the same value. Build-time. |
CHM_API_KEY_SECRET | — | Shared secret for chm_ API keys. When set, API-key auth is always on alongside the active provider. Issue keys at /api/v1/auth/api-key. |
Clerk (CHM_AUTH_PROVIDER=clerk)
Section titled “Clerk (CHM_AUTH_PROVIDER=clerk)”| Variable | Default | Description |
|---|---|---|
VITE_CLERK_PUBLISHABLE_KEY | — | Clerk publishable key (pk_...). Build-time — must be set before bun run build. |
CLERK_SECRET_KEY | — | Clerk secret key (sk_...). Runtime only. Never expose to the browser. |
CHM_CLERK_PUBLIC_READ | false | When true, anonymous visitors can view read-only monitoring content; writes (AI agent, control actions, arbitrary SQL) still require sign-in. Runtime only. See Clerk → Public read-only mode. |
Reverse proxy (CHM_AUTH_PROVIDER=proxy)
Section titled “Reverse proxy (CHM_AUTH_PROVIDER=proxy)”Trust a reverse proxy that already authenticated the user. Either mechanism below can authenticate a request.
Cloudflare Access JWT:
| Variable | Default | Description |
|---|---|---|
CHM_CF_ACCESS_TEAM_DOMAIN | — | Cloudflare Access team URL (https://<team>.cloudflareaccess.com). Enables Cf-Access-Jwt-Assertion JWT verification. |
CHM_CF_ACCESS_AUD | — | Access application AUD tag the JWT must carry. |
Trusted header (bare subject):
| Variable | Default | Description |
|---|---|---|
CHM_PROXY_AUTH_SECRET | — | Shared secret. When set, the identity header is honored only if this secret is also present (constant-time compare). Without it, the trusted-header mechanism is disabled. |
CHM_PROXY_SHARED_SECRET_HEADER | X-Chm-Proxy-Secret | Header the proxy sends containing the shared secret. |
CHM_PROXY_AUTH_HEADER | X-Forwarded-User | Header the proxy sends containing the authenticated user identity. |
When
CHM_PROXY_AUTH_SECRETis set, the identity header (X-Forwarded-Userby default) is honored only when the request also carries a matching shared-secret header (constant-time compared). WithoutCHM_PROXY_AUTH_SECRET, the entire trusted-header mechanism is disabled and identity headers are ignored.
Trusted reverse proxy (CHM_AUTH_PROVIDER=trusted)
Section titled “Trusted reverse proxy (CHM_AUTH_PROVIDER=trusted)”Use when an upstream proxy (oauth2-proxy, Authelia, Traefik ForwardAuth, nginx auth-url) forwards the user’s full identity as HTTP headers. Extracts a complete principal — name, email, avatar, groups, custom claims.
Trust gate — configure exactly one:
| Variable | Default | Description |
|---|---|---|
CHM_TRUSTED_AUTH_SECRET | — | Shared secret (runtime secret). The proxy must send it in CHM_TRUSTED_SHARED_SECRET_HEADER. Constant-time compared. Recommended. |
CHM_TRUSTED_ALLOW_INSECURE | false | When true, trusts headers with no secret check. Only safe when the service is unreachable except via the proxy (e.g. k8s ClusterIP). |
CHM_TRUSTED_SHARED_SECRET_HEADER | X-Chm-Proxy-Secret | Header name carrying the shared secret. |
Identity headers — all optional; defaults match common proxy conventions:
| Variable | Default | Populates |
|---|---|---|
CHM_TRUSTED_USER_HEADER | X-Forwarded-User | Subject / user id. Falls back to the email header. |
CHM_TRUSTED_EMAIL_HEADER | X-Forwarded-Email | Email address. |
CHM_TRUSTED_NAME_HEADER | X-Forwarded-Preferred-Username | Display name. |
CHM_TRUSTED_AVATAR_HEADER | X-Forwarded-Avatar | Avatar URL. |
CHM_TRUSTED_GROUPS_HEADER | X-Forwarded-Groups | Comma- or space-separated groups. |
CHM_TRUSTED_ROLE_HEADER | X-Forwarded-Role | Single role; merged into the groups list. |
CHM_TRUSTED_CUSTOM_HEADERS | — | Extra claims. Comma-separated field:Header-Name pairs, e.g. team:X-Forwarded-Team. |
Access control:
| Variable | Default | Description |
|---|---|---|
CHM_TRUSTED_ALLOWED_GROUPS | — | Comma-separated group names. When set, users whose forwarded groups do not intersect are denied 403. Case-insensitive. |
See Trusted proxy for setup examples (oauth2-proxy + Dex + Traefik, nginx).
AI Agent / LLM Provider
Section titled “AI Agent / LLM Provider”The agent uses an OpenAI-compatible API. Set LLM_API_KEY to enable it. Keep all LLM keys server-side — never prefix them with VITE_.
| Variable | Default | Description |
|---|---|---|
LLM_API_KEY | — | Provider API key (fallback when no provider-specific key is set). |
LLM_API_BASE | https://openrouter.ai/api/v1 | OpenAI-compatible API base URL. |
LLM_MODEL | openrouter:openrouter/free | Model identifier in provider:modelId form. |
LLM_EXTRA_MODELS | — | Additional model picker entries. Format: `provider:modelId[ |
Provider-specific keys
Section titled “Provider-specific keys”Provider-specific keys take priority over the generic LLM_API_KEY / LLM_API_BASE.
| Variable | Description |
|---|---|
OPENROUTER_API_KEY | OpenRouter API key. |
OPENROUTER_API_BASE | OpenRouter base URL. |
OPENROUTER_REFERER | HTTP referer sent to OpenRouter (for rankings). |
OPENROUTER_APP_NAME | App name sent to OpenRouter (for rankings). |
OPENROUTER_MODELS_API | OpenRouter models list endpoint (default https://openrouter.ai/api/v1/models). |
NVIDIA_API_KEY | NVIDIA NIM API key. |
NVIDIA_API_BASE | NVIDIA NIM base URL. |
ANYROUTER_API_KEY | AnyRouter API key. |
ANYROUTER_API_BASE | AnyRouter base URL. |
Agent behavior
Section titled “Agent behavior”| Variable | Default | Description |
|---|---|---|
AGENT_API_TOKEN | — | Shared Bearer token for the agent API (POST /api/v1/agent). Accepted when CHM_FEATURE_AGENT_ACCESS=authenticated. |
AGENT_ENABLE_CONTROL_TOOLS | false | Enable kill-query, optimize, and other write actions. Keep false unless users are trusted. |
See AI Agent — Configuration for full details.
Conversation Store
Section titled “Conversation Store”Agent conversations default to browser localStorage. Enable server-side persistence with two steps:
- Set
VITE_FEATURE_CONVERSATION_DB=trueat build time (this is aVITE_*variable — must be set beforebun run build). Also requires Clerk auth (VITE_AUTH_PROVIDER=clerk). - Configure a backend at runtime via
CONVERSATION_STORE_BACKEND.
| Variable | Default | Description |
|---|---|---|
VITE_FEATURE_CONVERSATION_DB | false | Build-time. Set true to enable server-side conversation persistence. Requires Clerk. Must be set before bun run build. |
CONVERSATION_STORE_BACKEND | (auto) | Runtime. Backend: agentstate, d1, postgres, or memory. When unset, the server auto-selects the first available backend (AgentState if key present → D1 binding → Postgres via DATABASE_URL → Memory). |
AgentState backend:
| Variable | Default | Description |
|---|---|---|
AGENTSTATE_API_KEY | — | AgentState API key. Required when CONVERSATION_STORE_BACKEND=agentstate. |
AGENTSTATE_BASE_URL | https://agentstate.app/api | AgentState API base URL. |
AGENTSTATE_AI_ENRICH | false | Set true to enable AI enrichment of stored conversations. |
Cloudflare D1 backend:
| Variable | Default | Description |
|---|---|---|
CONVERSATIONS_D1_DATABASE_ID | — | Cloudflare D1 database UUID for the CONVERSATIONS_D1 binding. |
AGENT_CONVERSATIONS_D1_DATABASE_ID | — | Alias for CONVERSATIONS_D1_DATABASE_ID. |
PostgreSQL backend:
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string. |
POSTGRES_URL | Alternative PostgreSQL connection string. |
POSTGRES_PRISMA_URL | Prisma-specific PostgreSQL connection string. |
See Conversation History — Backends for setup and fallback behavior.
AI Insights Store
Section titled “AI Insights Store”The AI Insights panel on /overview persists its findings through a pluggable store. It is additive opt-in and defaults to ClickHouse; the D1, Postgres, and AgentState backends reuse the conversation-store env above.
| Variable | Default | Description |
|---|---|---|
INSIGHTS_STORE_BACKEND | auto | Backend: auto, clickhouse, d1, postgres, agentstate, or memory. auto and clickhouse both use the ClickHouse monitoring_findings table. auto never silently follows other env; a selected backend missing its prerequisite falls back to ClickHouse. |
INSIGHTS_D1 | — | Optional dedicated D1 binding for the d1 backend. Falls back to CONVERSATIONS_D1 when unset. |
postgres reuses DATABASE_URL; agentstate reuses AGENTSTATE_API_KEY (+ optional AGENTSTATE_BASE_URL).
See AI Agent — AI Insights persistence for setup and fallback behavior. GET /api/v1/insights/backend reports the active backend.
PeerDB Monitoring
Section titled “PeerDB Monitoring”Optional. Set PEERDB_API_URL to enable the PeerDB section (Mirrors and Peers) in the sidebar.
| Variable | Default | Description |
|---|---|---|
PEERDB_API_URL | — | PeerDB REST API base URL. For the PeerDB UI (NextAuth), include /api suffix — e.g. https://peerdb.example.com/api. For the raw flow-api, use the bare origin — e.g. http://localhost:8113. |
PEERDB_PASSWORD | — | PeerDB password. Sent as HTTP Basic with an empty username. Server-side only. |
PEERDB_CACHE_TTL_MS | 10000 | Server-side response cache TTL in milliseconds. Set 0 to disable. |
PEERDB_CACHE_MAX_ENTRIES | 500 | Max cached PeerDB responses before oldest are evicted. |
PEERDB_FETCH_TIMEOUT_MS | 10000 | Upstream PeerDB request timeout in milliseconds. |
chmonitor proxies only a read-only allowlist of PeerDB endpoints; mutating operations (create/drop/pause, alert config) are rejected with 403.
## PeerDB UI behind NextAuthPEERDB_API_URL=https://peerdb.example.com/apiPEERDB_PASSWORD=your-peerdb-ui-password
## Raw flow-api (no auth)PEERDB_API_URL=http://localhost:8113Analytics & Branding
Section titled “Analytics & Branding”All client-side, all build-time. VITE_* for TanStack app; NEXT_PUBLIC_* for legacy Next.js.
| Variable | Default | Description |
|---|---|---|
VITE_TITLE_SHORT | ClickHouse | Browser tab title (short form). |
VITE_LOGO | — | Custom logo URL shown in the header. |
VITE_AUTOCOMPLETE_LIMIT | — | Max results in autocomplete dropdowns. |
VITE_MEASUREMENT_ID | — | Google Analytics measurement ID (G-...). |
VITE_SELINE_ENABLED | false | Enable Seline analytics. |
VITE_VERCEL_ANALYTICS | false | Enable Vercel Analytics. |
VITE_POSTHOG_KEY | — | PostHog project API key. |
VITE_POSTHOG_HOST | https://us.i.posthog.com | PostHog ingest host URL. |
Runtime & Build
Section titled “Runtime & Build”| Variable | Default | Description |
|---|---|---|
NODE_ENV | development | Runtime environment: development, production, test. |
ENABLE_CLOUDFLARE | false | Enable Cloudflare-specific build configuration. |
CLOUDFLARE_WORKERS | — | Set to 1 when running on Cloudflare Workers. |
CF_PAGES | — | Set automatically by Cloudflare Pages at runtime. |
MINIFLARE | — | Set to 1 when running locally with Miniflare. |
DOCS_CONTENT_ROOT | — | Override docs content source directory. |
Build-time only
Section titled “Build-time only”Injected at build time for the About page.
| Variable | Description |
|---|---|
VITE_GIT_SHA | Current commit SHA. |
VITE_GIT_REF | Current git branch or tag. |
VITE_BUILD_TIMESTAMP | ISO build timestamp. |
VITE_CI | Set to true in CI environments. |
Legacy / Migration
Section titled “Legacy / Migration”| Variable | Notes |
|---|---|
NEXT_PUBLIC_AUTH_PROVIDER | Renamed to VITE_AUTH_PROVIDER in v0.3. Old name still works as a fallback. |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | Renamed to VITE_CLERK_PUBLISHABLE_KEY in v0.3. |
NEXT_PUBLIC_FEATURE_CONVERSATION_DB | Deprecated alias for VITE_FEATURE_CONVERSATION_DB=true. |
NEXT_PUBLIC_AUTOCOMPLETE_LIMIT | Renamed to VITE_AUTOCOMPLETE_LIMIT in v0.3. |
NEXT_PUBLIC_RUNNING_QUERIES_REFRESH_MS | Renamed to VITE_RUNNING_QUERIES_REFRESH_MS in v0.3. |
CLICKHOUSE_EXCLUDE_USER_DEFAULT | Comma-separated usernames excluded from history-queries by default. |
See Migrate to v0.3 for the full rename list.