Fabric Emulator
v0.33.0latest release · docs built from latest-eec3e8c →A local Microsoft Fabric: the control plane, OneLake, and engines that genuinely run your code. Workspaces, items and their CI/CD definitions, workspace RBAC, git integration, jobs and the 202/poll long-running-operation contract, validating Microsoft Entra bearer tokens against entra-emulator exactly as real Fabric validates against Entra.
Microsoft's own tools drive it: fabric-cicd, the Fabric CLI, dbt-fabric, the Terraform provider, the VS Code extension. The same pipeline runs unmodified here and against a real tenant.
Every supported capability names the test that witnesses it, and CI fails when one loses its witness. Where something is a contract and not an engine, this page says which.
Testing Fabric work against Fabric means a tenant, a capacity and a cloud round trip for every iteration. The consequences are specific, and they are not really about speed.
A capacity is shared and always on. Nothing spins one up per branch, so the Fabric part of a change is the part continuous integration never exercises.
Here: `docker compose up`, per run, on the runnerOne run's cleanup is another run's broken fixture. Teams either serialise on a workspace or discover the collision as a failure in somebody else's job.
Here: a tenant per test, created and thrown awayThe deployment pipeline, the OneLake writes, the notebook that only fails on real data. They break in production because production was the first place they ran.
Here: the same code, offline, before it is pushedThat is the whole difficulty, and it is why this project spends more effort on evidence than on features. Real clients drive the surfaces, the differences that remain are written down rather than left to be discovered, and the same suite can be pointed at a real tenant with FABRIC_TARGET to find out where the two disagree.
One Go binary is the control plane and OneLake. The engines beside it are real, unmodified software: Sail for Spark, SQL Server for T-SQL, Microsoft's own Kusto container for KQL, Apache Kafka for Eventstream. No client knows it is not Fabric.
138 of 158 graded capabilities do real work.9 are a faithful contract without an engine, 3 need an engine that is not the default, and 8 are an honest 501. Each row below links to the page that carries the detail.
Workspaces, items and their CI/CD definitions, folders, workspace RBAC enforced from the validated bearer principal, git integration, deployment pipelines, jobs, and the 202/poll long-running-operation contract. Fabric Core MCP included.
07 — control-plane APIBoth dialects of the data plane, ADLS Gen2 and Blob, addressed as Fabric addresses them. Real Delta on disk with put-if-absent commit atomicity, shortcuts, and item-scoped OneLake security with RLS and CLS.
08 — OneLake ·54 — OneLake securitySail, a Rust Spark Connect implementation, is the default: sessions start in milliseconds and Delta is native. The JVM Spark overlay is available as an oracle when a surface needs a real JVM, and the two are measured against the same probes.
20 — the engine ·engine matrixA real TDS endpoint backed by SQL Server, so Microsoft's own drivers connect. Row-level security, column-level security and dynamic data masking are enforced by the database rather than filtered on the way out.
16 — warehouse ·29 — T-SQL parityData Factory pipelines with the expression language and control flow interpreted for real, activities dispatched to the engines above, and Apache Airflow jobs.
23 — deployment pipelinesKQL runs on Microsoft's own Kusto container and Eventstream on Apache Kafka, both behind an opt-in profile because most tests never reach them and the images are not small.
25 — RTI ·51 — EventstreamOne environment variable points the conformance suite at a real tenant instead of this one. That is the fidelity oracle: divergences found there become parity-map rows rather than surprises.
21 — real Fabric toggleOpenMetadata catalogues the emulated estate — workspaces, lakehouses, Delta tables — so lineage and glossary work has something to run against locally.
22 — OpenMetadataParity here is not self-assessed. 599 witnesses are mapped to125 claims, and a claim whose witness is renamed or deleted fails the build rather than quietly becoming an assertion.
| Kind | What it is | Why it ranks where it does |
|---|---|---|
ci: | A CI job in which a real third-party client does the talking | Strongest. A packaged release of somebody else's software, over a network, with no knowledge of this codebase |
sdk: | A Go test in which Microsoft's own client speaks the protocol | Third-party evidence too, but in-process rather than a released client over a network, so it ranks below ci: |
go: | A Go test: real HTTP, real signed JWTs, real RBAC | Our own client. Proves the code agrees with itself, which is the weakest thing a green test can mean |
boundary: | The claim is scoped by a documented limitation | Not a witness at all, and named as such, with the reason recorded beside it |
That gap cost real time twice here, so the checker detects skipped tests and gated jobs rather than taking a name on trust. The parity map is the ledger, its history shows how every row moved release by release, and ecosystem conformance lists the real clients driving it in CI.
The full ledger is the parity map. These are the entries most likely to matter before you start, stated here rather than found later.
| Capability | Status | What that means |
|---|---|---|
Java and Scala UDFs, spark.jars | not on the default engine | Sail has no JVM classloader, so a JAR is accepted and inert. The JVM overlay has a real one |
sc, the RDD API, spark._jvm | partly, by measurement | Spark Connect exposes no SparkContext or JVM bridge; the measured subset that does work is in the engine matrix rather than asserted |
| Structured streaming | partly | readStream plans, and durable sinks pull a micro-batch on the Livy path |
| Dataflow Gen2 | management only | The item and its definition round-trip; refresh and in-pipeline execution fail by name, because the Power Query M engine is not something to fake |
| Purview scanning and system classifiers | not implemented | A scan is an engine, and the ~200 built-in classifiers are proprietary detection patterns. This row can never move |
| On-prem gateways and connectors | not implemented | Absent rather than stubbed |
| Real-tenant conformance | gated, unwitnessed | The suite and the workflow exist; the secrets that would point them at a real tenant are unset, so that leg has never run — and a skipped run is not evidence |
Intentionally insecure: no real authorization boundary, self-signed TLS, seeded credentials. Run it on localhost only.
A single Go binary, or the container image. Homebrew and GHCR publish on every tag; winget lags, because Microsoft's moderation takes days.
brew install calvinchengx/tap/fabric-emulator
winget install calvinchengx.fabric-emulator
go install github.com/calvinchengx/fabric-emulator/cmd/fabric-emulator@latest
docker pull ghcr.io/calvinchengx/fabric-emulator:latestEvery option, including the archives and the compose files, is in installation. What each running mode costs in memory and startup time is in running modes.
One command brings up the control plane, OneLake, Entra, Key Vault and the compute sidecars, with Spark-compatible compute already attached. Check the machine first; make doctor names what is missing rather than letting it surface later as a broken recipe.
git clone https://github.com/calvinchengx/fabric-emulator
cd fabric-emulator
make doctor
docker compose up # or: make up, which adds OpenMetadata and AirflowThen mint a token, create a workspace and write to OneLake, in the quickstart — or take the medallion tutorial from bronze through gold. Allow the runtime 8 GB; the six default services idle at about 530 MB.