# Configuration Reference

The Application SDK reads configuration from environment variables at startup. Variables are grouped below by subsystem. The canonical source of truth is [`application_sdk/constants.py`](../application_sdk/constants.py) (import-time constants) and [`application_sdk/main.py`](../application_sdk/main.py) (`AppConfig` runtime values).

Set variables in your shell environment, a `.env` file at the project root, or Docker `ENV` / Kubernetes `ConfigMap` / `Secret` resources. See `.env.example` at the repo root for a ready-to-copy template.

---

## Application

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_APP_MODULE` | _(required)_ | App class to load: `module.path:ClassName` (e.g. `app.app:MyExtractor`). Startup fails without it. Set in your `Dockerfile` as `ENV ATLAN_APP_MODULE=…` or pass via `--app` CLI flag. |
| `ATLAN_APP_MODE` | `combined` | Run mode: `worker`, `handler`, or `combined`. Determines which subsystems start; override via `--mode` CLI flag. **v2-compat fallback:** `APPLICATION_MODE` (deprecated; mapped at startup to the equivalent v3 mode). |
| `ATLAN_APPLICATION_NAME` | `default` | Application name. Used in object-store paths, logging, and workflow identification. The `default` fallback applies to those *identity* uses only — task-queue derivation treats the variable as genuinely unset (see [Task-queue naming](#task-queue-naming)). Set it as the **bare** name, with no `atlan-` prefix; the SDK adds the prefix. |
| `ATLAN_DEPLOYMENT_NAME` | `local` | Deployment name. Distinguishes dev / staging / prod deployments of the same app. As with `ATLAN_APPLICATION_NAME`, the `local` fallback is an identity default and does not apply to task-queue derivation. |
| `ATLAN_TENANT_ID` | `default` | Tenant identifier for multi-tenant deployments. |
| `ATLAN_DOMAIN_NAME` | `atlan.com` | Tenant domain name. |
| `ATLAN_TEMPORARY_PATH` | `./local/tmp/` | Path for intermediate files during processing. |
| `ATLAN_CLEANUP_BASE_PATHS` | _(empty)_ | Comma-separated object-store prefixes cleaned up by `cleanup_files()`. Defaults to the workflow-scoped run path when unset. |
| `ATLAN_CONTRACT_GENERATED_DIR` | `app/generated` | Directory for generated contract JSON (configmaps, manifest). In Docker (`WORKDIR=/app`) this resolves to `/app/app/generated`. |
| `ATLAN_FRONTEND_ASSETS_PATH` | `app/generated/frontend/static` | Path to static frontend assets served by the handler. |

### Release metadata

Injected by the Local Marketplace into the Helm release at deploy time, and exposed to consumers via the OTel `target_info` gauge (one row per pod). Leave empty for local development.

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_APPLICATION_VERSION` | _(empty)_ | Semantic version of the app release (e.g. `1.2.3`). |
| `ATLAN_RELEASE_ID` | _(empty)_ | Release UUID from Global Marketplace. |
| `ATLAN_RELEASE_CHANNEL` | _(empty)_ | Release channel (`all`, `beta`, `staging`, `specific`). |
| `ATLAN_SDK_VERSION` | _(empty)_ | SDK version used to build this app image. |
| `ATLAN_APP_TYPE` | _(empty)_ | App type from Global Marketplace (e.g. `connector`, `system`). |
| `ATLAN_PUBLISHED_AT` | _(empty)_ | Release publication timestamp (ISO 8601). |

---

## Temporal / Workflow

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_TEMPORAL_HOST` | `localhost:7233` | Temporal server address (`host:port`). **v2-compat fallback:** if unset, the SDK constructs the address from `ATLAN_WORKFLOW_HOST` + `ATLAN_WORKFLOW_PORT` (deprecated; remove when all deployments set `ATLAN_TEMPORAL_HOST`). |
| `ATLAN_TEMPORAL_NAMESPACE` | `default` | Temporal namespace. **v2-compat fallback:** `ATLAN_WORKFLOW_NAMESPACE`. |
| `ATLAN_TASK_QUEUE` | _(derived)_ | Temporal task queue name. Defaults to `atlan-{ATLAN_APPLICATION_NAME}-{ATLAN_DEPLOYMENT_NAME}` when both are set, or just the bare app name (**no** `atlan-` prefix) when only `ATLAN_APPLICATION_NAME` is set, or `{ClassName}-queue` (kebab-case) when neither is set. Setting this explicitly also changes the queue the served manifest advertises, so a worker on an overridden queue and the Automation Engine stay in step. See [Task-queue naming](#task-queue-naming). |
| `ATLAN_TEMPORAL_PROMETHEUS_BIND_ADDRESS` | `127.0.0.1:9464` | Bind address for the Temporal SDK Prometheus endpoint (~40 built-in metrics). Loopback-only by default — operators should not scrape this port directly; combined-mode FastAPI `/metrics` proxies it in-process. See [Monitoring](concepts/monitoring.md). |
| `ATLAN_PREFLIGHT_GATE_MODE` | _(unset)_ | Deploy-time preflight gate posture override, read once at worker build. Only the literal `hard` enforces (blocks a `NOT_READY` run); any other set value resolves to soft. Empty or unset defers to the app's declared `App.preflight_gate_mode`. Set on the worker deployment; no app release needed. See [Apps](concepts/apps.md#preflight-gate-posture). |

### Task-queue naming

The queue name has to be agreed on by two things that never talk to each other: the **worker**, which polls it, and the **served manifest**, whose resolved `task_queue` the Automation Engine writes into the DAG and submits work to. When they disagree nothing fails loudly — AE submits to one queue, the worker polls another, and the run sits unclaimed until its 24h heartbeat backstop.

There is now one derivation, `application_sdk.common.task_queue.derive_task_queue`, and the manifest route does not re-run it — it stamps the queue the handler was configured with, which is the same value the worker was started on. Two paths deriving the same answer is a convention; one path copying the other's answer is structural.

The rule itself:

| `ATLAN_APPLICATION_NAME` | `ATLAN_DEPLOYMENT_NAME` | Queue |
|---|---|---|
| `dbt` | `prod` | `atlan-dbt-prod` |
| `dbt` | _(unset)_ | `dbt` — bare, **no** prefix |
| _(unset)_ | anything | no queue name exists; the worker falls back to `{ClassName}-queue` for local dev, and the manifest stamps that same queue. With no app name available anywhere, the served manifest leaves the literal `{app_name}` token in place and logs at ERROR |

Two consequences worth internalising when writing or rewriting an AE DAG outside the toolkit:

- **Pass the bare app name.** `derive_task_queue` adds the `atlan-` prefix. Prefixing a value that is already prefixed produces `atlan-atlan-dbt-production`, a queue nothing polls.
- **Never invent a name for the unset case.** `atlan-default-prod` reads as a legitimate queue and reproduces the original silent hang; a literal `{app_name}` in the DAG is greppable and diagnosable in one step. That is why `ATLAN_APPLICATION_NAME`'s `default` fallback is scoped to identity uses and excluded here.

Nodes that dispatch to a *different* app's queue (`atlan-publish-{deployment_name}` and friends) are legitimately not this app's queue: their `{deployment_name}` token is filled and the value is otherwise left alone.

### Worker Versioning

Used by the Temporal Worker Deployment controller (TWD). Leave empty unless your cluster uses versioned deployments.

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_APP_BUILD_ID` | _(empty)_ | Build ID for worker versioning. Fallback: `TEMPORAL_BUILD_ID`. |
| `ATLAN_APP_DEPLOYMENT_NAME` | _(empty)_ | Worker Deployment name (`<namespace>/<twd-name>`). Fallback: `TEMPORAL_DEPLOYMENT_NAME`. |

### Worker Restart Supervisor

Bounds the restart supervisor that rebuilds the worker after a fatal poll error (e.g. a transient auth failure) instead of exiting. Defaults are sensible; override only to tune restart behavior.

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_WORKER_MAX_CONSECUTIVE_RESTARTS` | `10` | Consecutive worker-fatal failures tolerated before the supervisor gives up and re-raises, so a persistent misconfiguration still fails loud instead of hot-looping. The counter resets after a healthy run window. |
| `ATLAN_WORKER_RESTART_BACKOFF_CAP_SECONDS` | `30` | Upper bound (seconds) for the full-jitter exponential backoff between worker restarts. The backoff is raced against shutdown so SIGTERM stays responsive. |
| `ATLAN_WORKER_HEALTHY_RUN_SECONDS` | `300` | A worker that ran at least this long (seconds) before failing is treated as a fresh incident, resetting the consecutive-failure streak. |

### TLS

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_TEMPORAL_TLS_ENABLED` | `false` | Enable mTLS for the Temporal connection. |
| `ATLAN_TEMPORAL_TLS_CA_CERT_PATH` | _(empty)_ | Path to the CA certificate file. |
| `ATLAN_TEMPORAL_TLS_CLIENT_CERT_PATH` | _(empty)_ | Path to the client certificate file. |
| `ATLAN_TEMPORAL_TLS_CLIENT_KEY_PATH` | _(empty)_ | Path to the client private key file. |
| `ATLAN_TEMPORAL_TLS_DOMAIN` | _(empty)_ | TLS server name override. |

---

## HTTP Handler

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_HANDLER_HOST` | `0.0.0.0` | Bind address for the FastAPI handler. Fallback: `ATLAN_APP_HTTP_HOST`. |
| `ATLAN_HANDLER_PORT` | `8000` | HTTP port for the handler. Fallback: `ATLAN_APP_HTTP_PORT`. |
| `ATLAN_HEALTH_PORT` | `8081` | Port for the worker health endpoint. |
| `ATLAN_HANDLER_MODULE` | _(empty)_ | Handler class to load (`module:ClassName`). Auto-discovered from the app module when unset. |
| `ATLAN_SHUTDOWN_DRAIN_DELAY_SECONDS` | `5` | Event-loop yield (seconds) before tearing down the worker transport, giving in-flight activity completion RPCs a chance to flush. Distinct from `TEMPORAL_GRACEFUL_SHUTDOWN_TIMEOUT`. |

---

## Authentication (Temporal)

Set these when `ATLAN_AUTH_ENABLED=true` to authenticate the worker and handler against a secured Temporal cluster.

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_AUTH_ENABLED` | `false` | Enable OAuth2 authentication for Temporal. |
| `ATLAN_AUTH_TOKEN_URL` | _(empty)_ | OAuth2 token endpoint. **v2-compat fallback:** `ATLAN_AUTH_URL`. |
| `ATLAN_AUTH_BASE_URL` | _(empty)_ | OAuth2 authorization base URL. **v2-compat fallback:** `ATLAN_AUTH_URL`. |
| `ATLAN_AUTH_CLIENT_ID` | _(empty)_ | OAuth2 client ID (direct env var). |
| `ATLAN_AUTH_CLIENT_SECRET` | _(empty)_ | OAuth2 client secret (direct env var). |
| `ATLAN_AUTH_SCOPES` | _(empty)_ | Space-separated OAuth2 scopes. |
| `ATLAN_DEPLOYMENT_SECRET_PATH` | `ATLAN_DEPLOYMENT_SECRETS` | Key name in the deployment secret store that holds the auth credentials. |
| `ATLAN_AUTH_CLIENT_ID_KEY` | `ATLAN_AUTH_CLIENT_ID` | Key name for the client ID within the deployment secret. |
| `ATLAN_AUTH_CLIENT_SECRET_KEY` | `ATLAN_AUTH_CLIENT_SECRET` | Key name for the client secret within the deployment secret. |

---

## Dapr Component Names

Dapr component names are read at module-import time (not at runtime) because the observability stack initialises before `AppConfig` exists.

| Variable | Default | Description |
|----------|---------|-------------|
| `STATE_STORE_NAME` | `statestore` | Dapr state store component name. |
| `SECRET_STORE_NAME` | `secretstore` | Dapr secret store component name. |
| `DEPLOYMENT_OBJECT_STORE_NAME` | `objectstore` | Dapr object store for workflow outputs and artifacts. |
| `UPSTREAM_OBJECT_STORE_NAME` | `atlan-objectstore` | Dapr object store for uploading data to the Atlan platform (SDR deployments only). If the named component is absent, `upstream_storage` is `None` and `App.upload()`/`App.download()` fall back to the deployment store. See [ADR-0014](adr/0014-two-store-storage-architecture.md). |
| `EVENT_STORE_NAME` | `eventstore` | Dapr pub/sub component name. |
| `DEPLOYMENT_SECRET_STORE_NAME` | `deployment-secret-store` | Dapr secret store holding deployment-scoped secrets (auth credentials, etc.). |
| `DAPR_MAX_GRPC_MESSAGE_LENGTH` | `104857600` (100 MB) | Maximum gRPC message size in bytes for Dapr client calls. Increase for apps that move large payloads through Dapr state or bindings. |

### Dapr Sidecar Readiness / Cold-Start Retry

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_DAPR_SIDECAR_WAIT_TIMEOUT` | `60` | Max seconds to poll `/v1.0/healthz` at startup for daprd to start accepting connections. Startup proceeds as soon as daprd answers the probe at all (per-component readiness is covered by each call site's cold-start retry budget); only connection errors poll to this deadline. Increase for pathologically slow cold starts (image pull + daprd boot). |
| `ATLAN_DAPR_COLD_START_MAX_WAIT_SECONDS` | `120.0` | Seconds a Dapr-backed call (secret fetch, credential-vault config fetch, ...) may retry a cold-sidecar race before giving up. Shared by every call site that opts into `retry_past_dapr_cold_start`. Env-overridable for pathologically slow runners. |

---

## Redis (Capacity Lock)

Used by `RedisCapacityPool` for distributed slot locking. Leave empty if you use `LocalCapacityPool` (default for local development when no Redis is configured).

| Variable | Default | Description |
|----------|---------|-------------|
| `REDIS_HOST` | _(empty)_ | Redis host for direct connection. Leave empty to use Sentinel. |
| `REDIS_PORT` | _(empty)_ | Redis port for direct connection. |
| `REDIS_PASSWORD` | _(empty)_ | Redis password. |
| `REDIS_SENTINEL_SERVICE_NAME` | `mymaster` | Redis Sentinel service name. |
| `REDIS_SENTINEL_HOSTS` | _(empty)_ | Comma-separated `host:port` pairs for Redis Sentinel. |
| `IS_LOCKING_DISABLED` | `true` | Disable distributed locking (safe default for local development). Set to `false` in production when using Redis. |
| `LOCK_RETRY_INTERVAL_SECONDS` | `60` | Retry interval for lock acquisition attempts. |

---

## MCP

| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_MCP` | `false` | Start an MCP server alongside the handler. Requires the `mcp` extra: `uv add "atlan-application-sdk[mcp]"`. |

---

## SQL Client

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_SQL_USE_SERVER_SIDE_CURSOR` | `true` | Use server-side cursors for SQL queries. Reduces memory for large result sets by streaming data row-by-row. Default: enabled. To disable, set the variable to any value other than `true` (e.g. `ATLAN_SQL_USE_SERVER_SIDE_CURSOR=false`). Matching is case-insensitive and surrounding whitespace is ignored. |

---

## Storage

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_MAX_CONCURRENT_STORAGE_TRANSFERS` | `4` | Maximum concurrent object-store uploads/downloads. |
| `ATLAN_OBSTORE_READ_TIMEOUT` | `90s` | **Progress-based** liveness bound: a transfer fails only if no bytes arrive for this long (the timer resets on every successful read). The primary timeout — a slow-but-progressing transfer survives; a genuine stall fails fast. |
| `ATLAN_OBSTORE_TIMEOUT` | `30m` | **Overall-request** wall-clock backstop per object-store request. Scales with file size, not throughput, so it is deliberately generous; `ATLAN_OBSTORE_READ_TIMEOUT` is the real liveness bound. |
| `ATLAN_STORAGE_RESUME_DOWNLOADS` | `true` | Kill-switch for resumable chunked downloads. When enabled, an interrupted chunked download keeps its partial file plus a `{path}.transfer-state` checkpoint sidecar, and a retry fetches only the missing ranges. Set to `false` to restore delete-partial-on-failure behaviour. |
| `ATLAN_STORAGE_PROGRESS_LOG_INTERVAL_SECONDS` | `30` | Interval (seconds) between in-progress heartbeat log lines during a long upload/download. `0` disables heartbeats. |
| `ATLAN_FILE_REF_CHUNKED_THRESHOLD_BYTES` | `33554432` (32 MiB) | FileReference size threshold above which downloads use parallel range GETs. |
| `ATLAN_FILE_REF_CHUNK_SIZE_BYTES` | `16777216` (16 MiB) | Size of each range-GET chunk in a chunked download. |
| `ATLAN_FILE_REF_CHUNK_CONCURRENCY` | `4` | Maximum concurrent range-GET chunks per file. |
| `ENABLE_ATLAN_UPLOAD` | `false` | Enable uploading processed artifacts to the Atlan platform object store. |
| `ATLAN_DEPLOYMENT_ARTIFACT_DUAL_WRITE` | `best_effort` | Controls dual-write behaviour when both stores are configured (SDR only). `best_effort` (default): artifact is written to the deployment (customer) store and the upstream (Atlan) store; a deployment-write failure logs a `WARNING` and the run continues. `required`: same dual-write, but a deployment-write failure causes the run to fail after the upstream write completes (a copy is guaranteed somewhere). `disabled`: upstream-only write (pre-BLDX-1464 behaviour). |
| `ATLAN_VALIDATE_ASSETS_ON_UPLOAD` | `true` | Validate transformed assets against the pyatlan_v9 backbone before the SDR→Atlan upload handoff. Warn-only — invalid/orphaned assets are logged, never block the upload. Set to `false` to disable the check entirely. |
| `ATLAN_VALIDATE_ASSETS_TIMEOUT_SECONDS` | `600` | Upper bound in seconds for one upload's asset-validation scan. The scan runs in an isolated child process (CNCT-85); past this bound the child is killed and the upload proceeds with a warning, so warn-only validation can neither stall nor crash a handoff. |
| `SSL_CERT_DIR` | _(empty)_ | Directory of custom CA certificates (`.pem`, `.crt`, `.cer`, `.ca-bundle`). Used by `httpx` and `aiohttp` clients when set. |

---

## Logging

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_LOG_LEVEL` | `INFO` | Log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`). **Fallback:** `LOG_LEVEL`. `CRITICAL` is accepted by loguru but prohibited in app code per [ADR-0011](adr/0011-logging-level-guidelines.md). |
| `ATLAN_LOG_BATCH_SIZE` | `100` | Records buffered before flushing to the object-store sink. |
| `ATLAN_LOG_FLUSH_INTERVAL_SECONDS` | `10` | Seconds between object-store sink flushes. |
| `ATLAN_LOG_RETENTION_DAYS` | `30` | Days to retain log files in the object store before cleanup. |
| `ATLAN_LOG_CLEANUP_ENABLED` | `false` | Enable automatic cleanup of old log files. Any non-empty string value (including `"false"`) is treated as `true` by `bool()`; unset or empty to disable. |
| `ATLAN_LOG_FILE_NAME` | `log.parquet` | Signal-type discriminator used internally to route records to the correct observability sub-path (logs / metrics / traces). **The default is kept as `log.parquet` for back-compat; the on-disk and object-store format is gzip-compressed NDJSON (`.json.gz`), not parquet.** |

---

## Metrics

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_METRICS_BATCH_SIZE` | `100` | Records buffered before flushing to the object-store sink. |
| `ATLAN_METRICS_FLUSH_INTERVAL_SECONDS` | `10` | Seconds between object-store sink flushes. |
| `ATLAN_METRICS_RETENTION_DAYS` | `30` | Days to retain metric files in the object store before cleanup. |
| `ATLAN_METRICS_CLEANUP_ENABLED` | `false` | Enable automatic cleanup of old metric files. Uses `.lower() == "true"` — safe to set to `"false"` to disable. |
| `ATLAN_ENABLE_TEMPORAL_CORE_METRICS` | `true` | Bind the Temporal Rust-core Prometheus endpoint at `ATLAN_TEMPORAL_PROMETHEUS_BIND_ADDRESS` (loopback) in worker/combined mode so its metric set (`temporal_workflow_*`, `temporal_activity_*`, etc.) is reachable for the combined-mode FastAPI `/metrics` proxy and the worker's `TemporalCoreCollector`. The FastAPI `/metrics` route is always exposed regardless of this flag — when this flag is `false`, or in handler-only mode, the response simply omits the proxied Temporal Rust-core families. `run_dev_combined()` defaults to `false` to avoid hot-reload port collisions. See [Monitoring](concepts/monitoring.md). |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_URL` | _(empty)_ | Pushgateway URL workers push to (split deployment). Empty disables push — combined-mode pods leave it unset and rely on direct `/metrics` scrape. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_INTERVAL_SECONDS` | `30` | Periodic push interval. A final push always happens on shutdown. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_DELETE_ON_SHUTDOWN` | `true` | DELETE the worker's group from the gateway on graceful shutdown so stopped pods don't leave sticky data. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_SWEEP_STALE_ON_START` | `true` | On worker startup, sweep stale `{job=mine, instance=other}` groups left by predecessors that died ungracefully. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_SWEEP_STALENESS_SECONDS` | `300` | Don't reap groups whose last push is more recent than this. Protects live siblings during rolling deploys. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_HTTP_TIMEOUT_SECONDS` | `10` | Per-request HTTP timeout for every Pushgateway call. |
| `ATLAN_PROMETHEUS_PUSHGATEWAY_SHUTDOWN_DELETE_DELAY_SECONDS` | `35` | Sleep between final push and DELETE on shutdown so Prometheus has at least one scrape window to read the final batch. |
| `ATLAN_TEMPORAL_CORE_METRICS_PROXY_TIMEOUT_SECONDS` | `5.0` | Per-request HTTP timeout (seconds) for the in-process FastAPI `/metrics` proxy fetching Temporal Rust-core series from `ATLAN_TEMPORAL_PROMETHEUS_BIND_ADDRESS` when the proxy is enabled. Increase if the loopback fetch times out under heavy load. |

---

## Traces

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_ENABLE_OTLP_TRACES` | `false` | Export traces via OTLP. |

---

## OpenTelemetry

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_SERVICE_NAME` | _(empty)_ | Runtime override for OTel service name. `AppConfig` reads this first; if set, it supersedes both `OTEL_SERVICE_NAME` and the name derived from the `--app` module. Import-time telemetry reads `OTEL_SERVICE_NAME` only — set both if you need consistent naming across all telemetry paths. |
| `OTEL_SERVICE_NAME` | `atlan-application-sdk` | Service name in telemetry data. At runtime, `AppConfig` overrides this with `ATLAN_SERVICE_NAME` (if set) or a name derived from the `--app` module; import-time telemetry (traces/metrics adaptors) reads only `OTEL_SERVICE_NAME` directly. |
| `OTEL_SERVICE_VERSION` | _(SDK version)_ | Service version in telemetry data. |
| `OTEL_RESOURCE_ATTRIBUTES` | _(empty)_ | Additional OTel resource attributes (key=value pairs). |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | OTLP collector endpoint. Set to the node IP collector in Kubernetes: `$(K8S_NODE_IP):4317`. |
| `ENABLE_OTLP_LOGS` | `false` | Export logs via OTLP to `OTEL_EXPORTER_OTLP_ENDPOINT`. |

| `OTEL_WF_NODE_NAME` | _(empty)_ | Kubernetes node name for workflow telemetry. |
| `OTEL_EXPORTER_TIMEOUT_SECONDS` | `30` | Timeout for OTLP export operations. |
| `OTEL_BATCH_DELAY_MS` | `5000` | Delay between batch exports (milliseconds). |
| `OTEL_BATCH_SIZE` | `512` | Maximum export batch size. |
| `OTEL_QUEUE_SIZE` | `2048` | Maximum export queue size. |
| `ATLAN_ENABLE_OBSERVABILITY_STORE_SINK` | `true` | Write observability data to the object store sink. **Fallback:** `ATLAN_ENABLE_OBSERVABILITY_DAPR_SINK`. |
| `ATLAN_BASE_URL` | _(empty)_ | Atlan instance base URL. Used by the events interceptor. |

---

## Segment

Segment events are automatically enabled when `ATLAN_SEGMENT_WRITE_KEY` is set.

| Variable | Default | Description |
|----------|---------|-------------|
| `ATLAN_SEGMENT_WRITE_KEY` | _(empty)_ | Segment write key. Leave empty to disable Segment tracking. |
| `ATLAN_SEGMENT_API_URL` | `https://api.segment.io/v1/batch` | Segment batch API URL. |
| `ATLAN_SEGMENT_BATCH_SIZE` | `100` | Maximum events per batch. |
| `ATLAN_SEGMENT_BATCH_TIMEOUT_SECONDS` | `10.0` | Maximum seconds to wait before flushing a partial batch. |

---

## AWS

| Variable | Default | Description |
|----------|---------|-------------|
| `AWS_SESSION_NAME` | `temp-session` | AWS session name for temporary credentials when assuming IAM roles. |

---

## Path Templates

These are code-level constants (not environment variables). Documented here for reference when interpreting object-store paths.

| Constant | Pattern |
|----------|---------|
| `WORKFLOW_OUTPUT_PATH_TEMPLATE` | `artifacts/apps/{application_name}/workflows/{workflow_id}/{run_id}` |
| `STATE_STORE_PATH_TEMPLATE` | `persistent-artifacts/apps/{application_name}/{state_type}/{id}/config.json` |
| `OBSERVABILITY_DIR` | `artifacts/apps/{application_name}/{deployment_name}/observability` |

---

## Common Patterns

### Local development

Most defaults work out of the box for local development with `uv run poe start-deps` (starts Dapr + Temporal). The key variables to override:

```bash
ATLAN_APP_MODULE=app.app:MyExtractor
ATLAN_APPLICATION_NAME=my-extractor
ATLAN_LOG_LEVEL=DEBUG
```

### Production deployment

```bash
ATLAN_APP_MODULE=app.app:MyExtractor          # required
ATLAN_TEMPORAL_HOST=temporal.internal:7233    # production Temporal cluster
ATLAN_TEMPORAL_NAMESPACE=my-namespace
ATLAN_AUTH_ENABLED=true
ATLAN_AUTH_TOKEN_URL=https://auth.internal/oauth2/token
ATLAN_AUTH_CLIENT_ID=…                        # or use deployment secret store
ATLAN_AUTH_CLIENT_SECRET=…
ENABLE_ATLAN_UPLOAD=true
ATLAN_ENABLE_TEMPORAL_CORE_METRICS=true       # default; binds Temporal Rust-core on 127.0.0.1:9464 (loopback) for combined /metrics proxy and worker pushes
# /metrics is always exposed on the FastAPI handler port (default 8000) — no env-var gate
# For worker-only pods (split deployment), set the Pushgateway URL instead:
# ATLAN_PROMETHEUS_PUSHGATEWAY_URL=http://prometheus-pushgateway.monitoring.svc.cluster.local:9091
```

### Performance tuning

```bash
ATLAN_MAX_CONCURRENT_STORAGE_TRANSFERS=8      # higher on fast network
DAPR_MAX_GRPC_MESSAGE_LENGTH=209715200        # 200 MB for large payloads
ATLAN_LOG_BATCH_SIZE=500                      # fewer flushes under load
```
