Configuration
zaanix.config.yaml, environment overrides and every setting that matters — security, database, auth, DuckDB, MCP, lakehouse, the AI model, cache and observability.
How configuration is resolved#
zaanix.config.yaml is loaded from $ZAANIX_CONFIG, ./zaanix.config.yaml, or /etc/zaanix/zaanix.config.yaml. Values may reference environment variables with ${VAR} / ${VAR:-default} (nesting allowed). Later sources win:
- Built-in defaults
- The YAML file
- Well-known short names (
PORT,JWT_SECRET,ENCRYPTION_KEY,ZAANIX_DATA_DIR,DATABASE_URL,OIDC_*,DUCKDB_MEMORY_LIMIT, …) - Generic overrides
ZAANIX__<SECTION>__<KEY>— for exampleZAANIX__DUCKDB__MAX_RESULT_ROWS=1000
The final object is validated with zod; the process refuses to start on invalid configuration. The effective, redacted config is available with zaanix config and GET /api/admin/config.
security#
| Setting | Notes |
|---|---|
jwt_secret, encryption_key | Required in NODE_ENV=production; ephemeral (with a warning) in development. encryption_key is a 32-byte hex string. |
data_jail_directory | Every DuckDB file read/write is confined here (ZAANIX_DATA_DIR). |
filesystem_mode | full (default, VS Code-like): add any local folder to the explorer, query files anywhere on the host, cloud sources on. sandboxed (multi-tenant): everything confined to the data directory, external access off unless enabled. |
enable_external_access | false blocks S3/GCS/HTTP/MotherDuck and extension installs in sandboxed mode. |
lock_configuration | DuckDB refuses SET/PRAGMA on hardened settings from any connection. |
allowed_extensions / blocked_extensions / allow_arbitrary_extensions | INSTALL/LOAD allow-list; the blocked list always applies. |
allow_registration, password_min_length | Self-service sign-up (off by default) and password policy. |
max_upload_bytes, allowed_upload_extensions | Upload limits. |
database#
metadata_url — sqlite://zaanix_meta.db (default) or postgres://user:pass@host:5432/db; run_migrations (default true) applies migrations at start.
auth#
| Setting | Notes |
|---|---|
strategy | local or oidc (Authorization Code + PKCE, stateless signed state). |
oidc.issuer_url, client_id, client_secret, redirect_uri, scopes | Standard OIDC client settings; the redirect defaults to <public_url>/api/auth/oidc/callback. |
oidc.admin_emails | Promotes SSO users to ADMIN. |
oidc.groups_claim | Claim carrying the user's IdP groups (default groups; Entra may use roles). |
oidc.admin_groups | IdP groups whose members become ADMIN on login (never demoted). |
oidc.sync_groups | Mirror IdP groups into ZAANIX teams on every login (default on). See Sharing & teams. |
bootstrap_admin.email / password | Created on first start when no users exist. |
duckdb#
| Setting | Notes |
|---|---|
default_memory_limit | 80% of host RAM or absolute (16GB). Per-workspace overrides in Settings › Workspace › Engine. |
default_threads, query_timeout_seconds | Per-workspace tunable. |
temp_directory | Spill directory. |
max_result_rows | Hard cap for UI result grids (default 5 000). |
max_cached_engines, engine_idle_ttl_seconds | Engine LRU size and idle eviction (default 32 / 30 min). |
default_database | Storage of a workspace created without an explicit database: file (default — a <name>.duckdb in the data directory that survives restarts) or memory (scratch). |
cloud_sync_delay_seconds | Quiet period after the last change before a cloud-backed workspace (s3:// gs:// r2:// az:// database) is pushed to its object (default 60). |
sync_scheduler_enabled | Run scheduled data syncs from this process (default on; off on replicas). |
extension_directory, preload_extensions | Where extensions live (pre-populated in the image) and which to load at start. |
export_ttl_seconds, export_max_rows | Server-side export files expire after the TTL. |
mcp#
default_page_size / max_page_size (50 / 200 rows per tool call), max_cell_chars (truncation), require_confirmation_for_mutations (the HITL gate, default on), sse_heartbeat_seconds.
lakehouse#
enabled, statement_timeout_seconds (Databricks warehouse statements, default 120), max_rows (rows returned to the grid from a warehouse), materialize_max_rows (rows pulled into a DuckDB table).
copilot#
provider (anthropic | openai | gemini | deepseek | openrouter | kimi | groq | mistral | xai | ollama | custom | bedrock | bedrock_agent | agentcore | none) — the deployment-time default; a model saved from Settings › AI › Model by an administrator takes precedence — model, api_key, base_url (Ollama / OpenAI-compatible), aws_region, bedrock_agent_id, bedrock_agent_alias_id, agentcore_runtime_arn, allow_byok (users may bring their own key), max_context_tables, include_summaries, max_output_tokens, temperature.
cache#
| Setting | Notes |
|---|---|
enabled | Server-side result cache (default on). |
max_bytes | LRU budget (default 256 MB). |
max_entry_bytes | Results above this are never cached (default 16 MB). |
ttl_seconds | Lifetime of versioned entries — local files + workspace data epoch (default 6 h). |
remote_ttl_seconds | Lifetime of entries touching remote / lakehouse / MotherDuck sources (default 60 s; 0 never caches them). |
See Result cache for how keys are built.
mosaic#
| Setting | Notes |
|---|---|
enabled | The Mosaic connector endpoint behind the Explore view and Mosaic dashboards (default on). |
schema | Schema for Mosaic's pre-aggregated tables (default zaanix_mosaic); source views are <schema>_src_<hash> in the main schema. Both are dropped when the data epoch moves and hidden from catalogs. |
max_rows | Row ceiling for chart queries, independent of the grid cap (default 1 000 000). |
materialize_max_rows | Dashboard datasets up to this many rows are materialised once into an attached in-memory database so interactions read memory instead of re-parsing files (default 20 000 000; 0 = always views). |
rate_limit_per_minute | The connector's own budget, per session rather than per IP (default 6 000; 0 = unlimited). A brush over 25 charts is 25–75 requests, so the global server.rate_limit_per_minute no longer throttles dashboards. |
See Interactive exploration & Mosaic dashboards.
apps#
Streamlit data apps run by ZAANIX (see Data apps).
| Setting | Notes |
|---|---|
enabled | Default: on in filesystem_mode: full, off in sandboxed — apps execute Python next to the server. |
runtime | subprocess (a streamlit run per app). |
python | Interpreter used to create the virtualenv (needs venv and pip; default python3). |
venv_dir | The shared virtualenv (default <data dir>/.zaanix/apps/venv). |
auto_install | Create the virtualenv and install streamlit, pandas, pyarrow and the SDK on first start (default on). |
allow_requirements | Install each app's requirements.txt before it starts (default on). |
max_running, idle_stop_minutes | At most this many apps at once (5); stop an app nobody used for this long (30). |
port_range | Ports for the apps' own servers, local only (default [8601, 8700]). |
start_timeout_seconds | How long the health check may take (180). |
token_ttl_hours | Lifetime of the read-only, workspace-scoped token minted per start (24). |
max_source_bytes | Size limit of an app's source files (512 KiB). |
chrome_path | Chrome / Chromium for preview_app screenshots; auto-detected (macOS app bundle, google-chrome, chromium) when unset. The container image does not ship a browser — mount one or use a sidecar to get screenshots there. |
observability#
metrics_enabled, metrics_require_auth (Prometheus at /metrics), otel.enabled, otel.service_name, otel.exporter_otlp_endpoint, otel.console_exporter.
Example#
server:
port: ${PORT:-4200}
public_url: "${ZAANIX_PUBLIC_URL:-}"
security:
jwt_secret: "${JWT_SECRET}"
encryption_key: "${ENCRYPTION_KEY}"
data_jail_directory: "${ZAANIX_DATA_DIR:-./data}"
filesystem_mode: "${ZAANIX_FILESYSTEM_MODE:-full}"
database:
metadata_url: "${DATABASE_URL:-sqlite://zaanix_meta.db}"
auth:
strategy: "${AUTH_STRATEGY:-local}"
oidc:
groups_claim: "${OIDC_GROUPS_CLAIM:-groups}"
admin_groups: []
sync_groups: true
duckdb:
default_memory_limit: "${DUCKDB_MEMORY_LIMIT:-80%}"
query_timeout_seconds: ${DUCKDB_QUERY_TIMEOUT_SECONDS:-60}
cache:
max_bytes: ${ZAANIX_CACHE_MAX_BYTES:-268435456}