Skip to main content

Topaz vs Azurite: what actually works locally and what doesn't

· 20 min read
Kamil Mrzygłód
Topaz maintainer & contributor

If you have ever written a line of Azure code on a laptop, you have used Azurite. It is the official local emulator for Azure Storage, ships in every Visual Studio install, and runs unchanged in tens of thousands of CI pipelines. For Storage-only workloads it is an excellent tool — Microsoft maintains it, Azure SDKs target it, and the parity with the real Azure Storage REST API is strong.

The problem is that real applications stop at Azure Storage roughly never. The moment you reach for a secret in Key Vault, publish a message to Service Bus, push an image to a Container Registry, or want a DefaultAzureCredential chain that does not silently fall back to interactive browser auth, Azurite has nothing to offer. You are left bolting together a Service Bus emulator from a community Docker image, mocking the Key Vault SDK in tests, and hoping that the way your CI fakes Entra tokens does not drift away from how production behaves.

Topaz is a single .NET 8 (and when 1.3 version is released - .NET 10) binary that emulates Azure Storage, Key Vault, Service Bus, Event Hubs, Container Registry, Managed Identity, RBAC, ARM, and a working Entra ID layer in one process. This post is an honest comparison between the two, focused on what developers who already know Azurite actually run into.

Two days chasing a SharedKey signature mismatch: how we fixed azurerm_storage_table_entity in Topaz

· 10 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Some bugs announce themselves loudly. A null pointer in a hot path, a missing route that returns 404 to every request — the kind of thing that fails immediately and points straight at the cause. Others are quieter. They let most of the stack work correctly and only reveal themselves at the intersection of two independently correct but mutually incompatible assumptions. The azurerm_storage_table_entity failure was the second kind.

This post is an account of a two-day investigation into a persistent 401 Unauthorized response on Terraform table entity operations, the four separate bugs we found along the way, and how pairing with GitHub Copilot shaped the investigation. The fix touched authentication, HTTP routing, upsert semantics, and stream lifecycle — each uncovered only after the previous one was resolved.

Cancelling ARM deployments in Topaz — what it means for an emulator

· 5 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Cancelling an in-progress deployment is one of those ARM operations that looks simple from the outside — you POST to a /cancel endpoint and the deployment stops. Under the hood, what "stop" means depends entirely on whether the engine executing the deployment can be interrupted mid-flight. In a real emulator, that question has a more nuanced answer than in the real Azure control plane.

This post walks through how Topaz implements POST .../deployments/{name}/cancel, what constraints the orchestrator model imposes, and where the emulation intentionally diverges from Azure's behaviour.

Topaz Weekly Pulse #1: Major Storage milestones and cleaner automation workflows

· 5 min read
Kamil Mrzygłód
Topaz maintainer & contributor

This week in Topaz: from page blobs to health-checked host orchestration.

This is the first post in a new weekly series: Topaz Ship Log.

Each edition is a concise, case-by-case summary of what changed in Topaz during the week, why it matters, and what it unlocks for local Azure development. This first issue covers the last 7 days of work.

How we split Topaz CLI from the Host — and why it matters for scripting

· 6 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Until recently, topaz start was the only way to run the emulator. That single command lived inside the CLI, started the Host, and stayed running in your terminal. Useful for getting going quickly. Less useful once you want to script around it, automate it in CI, or distribute the two halves independently.

This post walks through why the split was done, how the boundary between Host and CLI works in practice, and what the health-check endpoint makes possible from any language.

Running Terraform against Azure locally, without a subscription

· 5 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Every Terraform workflow that targets Azure needs the same things before it can do anything useful: an Azure subscription, a service principal or user account with the right permissions, and a network path to the Azure APIs. In a team setting you also need to make sure those credentials are available wherever terraform apply runs — local machines, CI agents, staging pipelines. The feedback loop is slow, and the blast radius for a misconfigured apply is real.

Topaz removes all of that. The same terraform apply that would create resources in Azure can instead create them in a local emulator, with no subscription, no credentials to rotate, and no cloud charges. This post explains how the integration works and how to set it up.

How Topaz CI runs only the tests that matter

· 6 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Running the full test suite on every commit is simple to set up and expensive to live with. Topaz spans twelve services, each with its own E2E tests and Azure CLI tests. On a change to a single endpoint in the Container Registry service, waiting for Key Vault, Service Bus, and Event Hubs tests to finish is pure overhead. The Topaz CI pipeline solves this with a three-stage decision that maps changed files to a focused test filter — running everything only when it has to.

How Topaz emulates the Azure Container Registry data plane

· 7 min read
Kamil Mrzygłód
Topaz maintainer & contributor

Container Registry is different from every other Azure service Topaz emulates. You do not call it through the Azure SDK with a credential — you call it through the Docker CLI, docker pull, docker push, helm push, or any OCI-compliant client. Before any of that works, the client has to authenticate. And that authentication flow is entirely its own protocol, separate from anything in the Azure REST API.

This post walks through how Topaz emulates the ACR data plane authentication layer and what design decisions made it possible without writing a custom token server.

Star on GitHub