Get started

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:

  1. Built-in defaults
  2. The YAML file
  3. Well-known short names (PORT, JWT_SECRET, ENCRYPTION_KEY, ZAANIX_DATA_DIR, DATABASE_URL, OIDC_*, DUCKDB_MEMORY_LIMIT, …)
  4. Generic overrides ZAANIX__<SECTION>__<KEY> — for example ZAANIX__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#

SettingNotes
jwt_secret, encryption_keyRequired in NODE_ENV=production; ephemeral (with a warning) in development. encryption_key is a 32-byte hex string.
data_jail_directoryEvery DuckDB file read/write is confined here (ZAANIX_DATA_DIR).
filesystem_modefull (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_accessfalse blocks S3/GCS/HTTP/MotherDuck and extension installs in sandboxed mode.
lock_configurationDuckDB refuses SET/PRAGMA on hardened settings from any connection.
allowed_extensions / blocked_extensions / allow_arbitrary_extensionsINSTALL/LOAD allow-list; the blocked list always applies.
allow_registration, password_min_lengthSelf-service sign-up (off by default) and password policy.
max_upload_bytes, allowed_upload_extensionsUpload 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#

SettingNotes
strategylocal or oidc (Authorization Code + PKCE, stateless signed state).
oidc.issuer_url, client_id, client_secret, redirect_uri, scopesStandard OIDC client settings; the redirect defaults to <public_url>/api/auth/oidc/callback.
oidc.admin_emailsPromotes SSO users to ADMIN.
oidc.groups_claimClaim carrying the user's IdP groups (default groups; Entra may use roles).
oidc.admin_groupsIdP groups whose members become ADMIN on login (never demoted).
oidc.sync_groupsMirror IdP groups into ZAANIX teams on every login (default on). See Sharing & teams.
bootstrap_admin.email / passwordCreated on first start when no users exist.

duckdb#

SettingNotes
default_memory_limit80% of host RAM or absolute (16GB). Per-workspace overrides in Settings › Workspace › Engine.
default_threads, query_timeout_secondsPer-workspace tunable.
temp_directorySpill directory.
max_result_rowsHard cap for UI result grids (default 5 000).
max_cached_engines, engine_idle_ttl_secondsEngine LRU size and idle eviction (default 32 / 30 min).
default_databaseStorage 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_secondsQuiet period after the last change before a cloud-backed workspace (s3:// gs:// r2:// az:// database) is pushed to its object (default 60).
sync_scheduler_enabledRun scheduled data syncs from this process (default on; off on replicas).
extension_directory, preload_extensionsWhere extensions live (pre-populated in the image) and which to load at start.
export_ttl_seconds, export_max_rowsServer-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#

SettingNotes
enabledServer-side result cache (default on).
max_bytesLRU budget (default 256 MB).
max_entry_bytesResults above this are never cached (default 16 MB).
ttl_secondsLifetime of versioned entries — local files + workspace data epoch (default 6 h).
remote_ttl_secondsLifetime of entries touching remote / lakehouse / MotherDuck sources (default 60 s; 0 never caches them).

See Result cache for how keys are built.

mosaic#

SettingNotes
enabledThe Mosaic connector endpoint behind the Explore view and Mosaic dashboards (default on).
schemaSchema 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_rowsRow ceiling for chart queries, independent of the grid cap (default 1 000 000).
materialize_max_rowsDashboard 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_minuteThe 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).

SettingNotes
enabledDefault: on in filesystem_mode: full, off in sandboxed — apps execute Python next to the server.
runtimesubprocess (a streamlit run per app).
pythonInterpreter used to create the virtualenv (needs venv and pip; default python3).
venv_dirThe shared virtualenv (default <data dir>/.zaanix/apps/venv).
auto_installCreate the virtualenv and install streamlit, pandas, pyarrow and the SDK on first start (default on).
allow_requirementsInstall each app's requirements.txt before it starts (default on).
max_running, idle_stop_minutesAt most this many apps at once (5); stop an app nobody used for this long (30).
port_rangePorts for the apps' own servers, local only (default [8601, 8700]).
start_timeout_secondsHow long the health check may take (180).
token_ttl_hoursLifetime of the read-only, workspace-scoped token minted per start (24).
max_source_bytesSize limit of an app's source files (512 KiB).
chrome_pathChrome / 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}