Skip to content

Configuration

Everything is an environment variable (FABRIC_*); flags override env; then validation derives dependent values. There is no config file.

EnvFlagMeaning
FABRIC_ENTRA_ISSUER-entra-issuerThe exact iss bearer tokens must carry — an entra-emulator issuer (https://entra-emulator:8443/{tenant}/v2.0) or a real Entra tenant (https://login.microsoftonline.com/{tenant}/v2.0). Startup fails without it.
EnvFlagDefaultMeaning
FABRIC_ADDR-addr:9443Listen address.
FABRIC_DATA_DIR-data-dir./dataSQLite + TLS state directory, so workspaces, items and OneLake contents survive a restart. Set it to the empty string for a fully in-memory run (fresh DB and ephemeral cert — ideal for tests): unset and set-empty differ deliberately, and the compose files use the empty form so a throwaway stack leaves nothing behind. The Docker image sets /data.
FABRIC_ENTRA_JWKS_URL-entra-jwks-urlderivedWhere signing keys are fetched. Derived from the issuer by the Entra convention: {origin}/{tenant}/v2.0{origin}/{tenant}/discovery/v2.0/keys. Set explicitly only when the JWKS lives elsewhere (e.g. reachable under a different host than the advertised issuer).
FABRIC_ENTRA_TLS_INSECURE-entra-tls-insecurefalseSkip TLS verification when fetching the JWKS — needed when entra-emulator serves its self-signed cert (the compose file sets it). Never needed against real Entra.
FABRIC_AKV_VAULT_HOST(none)One extra host:port a vault secret reference may resolve against, besides Azure’s own *.vault.azure.net and the sovereign equivalents. The compose file sets keyvault-emulator:8444. This is a security boundary: resolving a reference sends a vault-audience bearer token to the host the connection names, so anything unlisted is refused — otherwise a hostile vaultURI exfiltrates the token, and (pointed at a real tenant) a real Azure one. Azure constrains the URI the same way.
FABRIC_ARM_URL-arm-url(none for the binary; this repo’s compose sets it)arm-emulator origin. Microsoft.Fabric/capacities created over ARM appear on GET /v1/capacities. The binary still defaults to empty, so a bare fabric-emulator is standalone; the compose runs arm-emulator and points at it, because capacities ARE ARM resources and a stack without one is a visibly smaller Fabric. Set FABRIC_ARM_URL= explicitly empty to opt back out to the seeded local capacity — standalone fabric-cicd works either way.
FABRIC_ARM_POLL_SECONDS-arm-poll-seconds5How often the ARM capacities feed is refreshed. 0 uses the 5s default. A transient ARM outage leaves last-known capacities in place.
FABRIC_DISABLE_TLS-disable-tlsfalseServe plain HTTP instead of self-signed TLS. Handy for curl exploration or behind a TLS-terminating proxy.
-lro-delay0Virtual seconds an async operation stays Running before succeeding. 0 = completes on the next poll. Combine with clock control for deterministic polling tests.

Booleans accept 1, true, yes, on (case-insensitive); anything else is false. Retry-After on 202 responses is fixed at 1 second.

Empty by default for the bare binary — leave them unset and unattached surfaces answer with an honest 501, not a fake result. Point them at running sidecars to route to real compute; see real compute and warehouse TDS for the full setup.

docker compose up sets FABRIC_SPARK_AGENT_URL/FABRIC_SQL_TDS_ADDR/ FABRIC_WAREHOUSE_SQL_URL for you by default (via the auto-loaded docker-compose.override.yml, which also brings up the sidecars they point at) — the binary’s own empty defaults below only apply if you run it directly, or opt out with docker compose -f docker-compose.yml up.

EnvFlagDefaultMeaning
FABRIC_SPARK_LIVY_URL-spark-livy-url(empty)Livy endpoint for real Spark session/statement execution.
FABRIC_SPARK_AGENT_URL-spark-agent-url(empty)Spark agent endpoint fronting the Livy cluster.
FABRIC_SQL_TDS_ADDR-sql-tds-addr(empty)TDS listen address for the SQL analytics endpoint.
FABRIC_WAREHOUSE_SQL_URL-warehouse-sql-url(empty)Backing SQL engine URL for warehouse query execution.
FABRIC_TENANT_ADMINS-tenant-admins(empty)Comma-separated principal ids (oid, or appid for a service principal) that count as Fabric administrators for /v1/admin/*. The gate is graded as Microsoft documents it: a read needs a Fabric administrator or a service principal, a write needs a Fabric administrator with no service-principal escape. Empty means nobody is an administrator, so every admin mutation is refused — the honest default, since the alternative is the pre-gate behaviour where every authenticated caller could create governance domains. Membership is declared here, never inferred from a token claim.
FABRIC_WEB_ACTIVITY-web-activityrealstub makes pipeline Web activities record success without calling anything — for a CI leg that must not reach the network. The default performs the real HTTP request, because a fabricated response is a false pass.
FABRIC_CUSTOM_ACTIVITY-custom-activityrealoff makes pipeline Custom (Azure Batch) activities refuse by name so no command reaches the Spark agent. The default runs the command in the agent’s container, matching a notebook cell on that same machine. The old opt-in spelling shell remains on.
FABRIC_AIRFLOW_URL-airflow-url(empty)Apache Airflow 2.10 REST API base URL. Setting it enables real ApacheAirflowJob execution.
FABRIC_AIRFLOW_DAG_DIR-airflow-dag-dir(empty)Host path shared with Airflow’s DAG folder. Required when FABRIC_AIRFLOW_URL is set.
FABRIC_AIRFLOW_USERNAME-airflow-username(empty)Optional Airflow REST basic-auth username.
FABRIC_AIRFLOW_PASSWORD-airflow-password(empty)Optional Airflow REST basic-auth password.
FABRIC_MLFLOW_URL-mlflow-url(empty)Real MLflow tracking/model-registry server base URL. Enables the workspace-scoped MLflow proxy and typed experiment/model synchronization.
FABRIC_KAFKA_BOOTSTRAP-kafka-bootstrap(empty)Apache Kafka broker host:port behind Eventstream items. Empty → item create still works (mgmt) and Spark / Custom-source execution 501s. See 51-eventstream-kafka.md.
FABRIC_DATABRICKS_URL-databricks-url(empty)databricks-emulator (or real workspace) origin. When set, DatabricksNotebook / DatabricksSparkPython submit there and dbfs: / /Workspace paths become legal. Empty keeps local Spark-agent termination and refuses those paths by name.
FABRIC_DATABRICKS_TOKEN-databricks-token(empty)PAT or OIDC access token sent to FABRIC_DATABRICKS_URL.
FABRIC_DATABRICKS_TLS_INSECURE-databricks-tls-insecurefalseSkip TLS verification for FABRIC_DATABRICKS_URL (databricks-emulator’s self-signed cert).
FABRIC_DAX_URL(empty)HTTP origin of a DAX pump in front of msmdsrv (POST /v1/deploy then POST /v1/dax). Empty keeps the in-process bounded evaluator — and is what GitHub-hosted ubuntu/mac CI tests. Set-but-unreachable is a 502, not a fallback. Not a compose default, and not a macos-latest / ubuntu-latest sidecar — 52-msmdsrv-hosts.md.
CommandDoes
fabric-emulator versionprints the release version (dev for source builds)
fabric-emulator healthcheckprobes /health on the local instance (honors FABRIC_ADDR), exit 0 when healthy — this is the Docker image’s HEALTHCHECK, since distroless has no shell

fabric-emulator compares the token’s iss claim string-exactly against FABRIC_ENTRA_ISSUER. Tokens carry whatever issuer entra-emulator advertises (its login origin), which is not automatically the hostname you fetch the JWKS from. On the compose network entra is therefore told to advertise the network-internal origin:

entra-emulator:
environment:
ORIGIN_MODE: compat
PUBLIC_ORIGIN: "https://entra-emulator:8443"

so iss = https://entra-emulator:8443/{tenant}/v2.0 = what fabric validates. If tokens are rejected with an issuer mismatch, this alignment is almost always the cause. See TLS & hosts for the full story.