Skip to content
Get Started for Free

Event Hubs

Azure Event Hubs is a real-time data streaming platform that ingests and processes millions of events per second. Producers append events to partitioned logs, and consumers read those logs independently at their own pace, which makes Event Hubs a common backbone for telemetry pipelines, event sourcing, and stream analytics. It exposes its data plane over AMQP 1.0, HTTPS, and a Kafka-compatible endpoint. For more information, see What is Azure Event Hubs?

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Event Hubs. The supported APIs are available on our API Coverage section, which provides information on the extent of Event Hubs’ integration with LocalStack.

This guide is designed for users new to Event Hubs and assumes basic knowledge of the Azure CLI and our lstk az proxy.

Launch LocalStack using your preferred method. For more information, see Introduction to LocalStack for Azure. Once the container is running, enable Azure CLI interception by running:

Terminal window
lstk az start-interception

This command points the az CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API. To revert this configuration, run:

Terminal window
lstk az stop-interception

This reconfigures the az CLI to send commands to the official Azure management REST API.

Create a resource group to contain your Event Hubs resources:

Terminal window
az group create \
--name rg-eventhubs-demo \
--location westeurope
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo",
"location": "westeurope",
"managedBy": null,
"name": "rg-eventhubs-demo",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}

Create an Event Hubs namespace in the resource group:

Terminal window
az eventhubs namespace create \
--resource-group rg-eventhubs-demo \
--name ehnsdoc42 \
--location westeurope \
--sku Standard
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.EventHub/namespaces/ehnsdoc42",
"name": "ehnsdoc42",
"location": "westeurope",
"kafkaEnabled": true,
"provisioningState": "Succeeded",
"serviceBusEndpoint": "https://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4511",
"sku": {
"capacity": 1,
"name": "Standard",
"tier": "Standard"
},
"status": "Active",
...
}

Create an event hub in the namespace:

Terminal window
az eventhubs eventhub create \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--name orders-hub \
--partition-count 4 \
--cleanup-policy Delete \
--retention-time 168
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.EventHub/namespaces/ehnsdoc42/eventhubs/orders-hub",
"name": "orders-hub",
"location": "westeurope",
"messageRetentionInDays": 7,
"partitionCount": 4,
"partitionIds": [
"0",
"1",
"2",
"3"
],
"retentionDescription": {
"cleanupPolicy": "Delete",
"retentionTimeInHours": 168
},
"status": "Active",
"type": "Microsoft.EventHub/namespaces/eventhubs",
...
}

Create a consumer group for the event hub:

Terminal window
az eventhubs eventhub consumer-group create \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--eventhub-name orders-hub \
--name analytics
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.EventHub/namespaces/ehnsdoc42/eventhubs/orders-hub/consumergroups/analytics",
"name": "analytics",
"type": "Microsoft.EventHub/namespaces/eventhubs/consumergroups",
...
}

List the consumer groups of the event hub:

Terminal window
az eventhubs eventhub consumer-group list \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--eventhub-name orders-hub \
--query "[].name" -o json
Output
[
"$Default",
"analytics"
]

Manage authorization rules and connection strings

Section titled “Manage authorization rules and connection strings”

Create a send-only authorization rule on the event hub:

Terminal window
az eventhubs eventhub authorization-rule create \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--eventhub-name orders-hub \
--name send-policy \
--rights Send
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.EventHub/namespaces/ehnsdoc42/eventhubs/orders-hub/authorizationRules/send-policy",
"name": "send-policy",
"rights": [
"Send"
],
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationrules"
}

List the connection strings for the rule:

Terminal window
az eventhubs eventhub authorization-rule keys list \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--eventhub-name orders-hub \
--name send-policy
Output
{
"keyName": "send-policy",
"primaryConnectionString": "Endpoint=sb://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4511/;SharedAccessKeyName=send-policy;SharedAccessKey=...;UseDevelopmentEmulator=true;EntityPath=orders-hub",
"primaryKey": "...",
"secondaryConnectionString": "Endpoint=sb://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4511/;SharedAccessKeyName=send-policy;SharedAccessKey=...;UseDevelopmentEmulator=true;EntityPath=orders-hub",
"secondaryKey": "..."
}

The namespace-level RootManageSharedAccessKey rule is created automatically with the namespace:

Terminal window
az eventhubs namespace authorization-rule keys list \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--name RootManageSharedAccessKey
Output
{
"keyName": "RootManageSharedAccessKey",
"primaryConnectionString": "Endpoint=sb://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4511/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=...;UseDevelopmentEmulator=true",
...
}

The Event Hubs runtime REST API accepts events on the namespace endpoint. Send a single event to the event hub:

Terminal window
curl -sk -i -X POST \
"https://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4566/orders-hub/messages" \
-H "Authorization: SharedAccessSignature sr=...&sig=...&se=...&skn=RootManageSharedAccessKey" \
-H "Content-Type: application/json" \
-d '{"orderId": 1001, "status": "created"}'
Output
HTTP/2 201
server: TwistedWeb/26.4.0
content-type: application/xml; charset=utf-8
content-length: 0

Route an event to a specific partition by partition key using the BrokerProperties header:

Terminal window
curl -sk -i -X POST \
"https://ehnsdoc42.servicebus.azure.localhost.localstack.cloud:4566/orders-hub/messages" \
-H "Authorization: SharedAccessSignature sr=...&sig=...&se=...&skn=RootManageSharedAccessKey" \
-H 'BrokerProperties: {"PartitionKey": "customer-42"}' \
-H "Content-Type: application/json" \
-d '{"orderId": 1002, "status": "created"}'
Output
HTTP/2 201
server: TwistedWeb/26.4.0
content-type: application/xml; charset=utf-8
content-length: 0

Event Hubs Capture archives the event stream into a storage account as Avro files. Create a storage account for the archives:

Terminal window
az storage account create \
--resource-group rg-eventhubs-demo \
--name stehcapturels \
--location westeurope \
--sku Standard_LRS
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.Storage/storageAccounts/stehcapturels",
"name": "stehcapturels",
"kind": "StorageV2",
"location": "westeurope",
"primaryEndpoints": {
"blob": "https://stehcapturels.blob.core.azure.localhost.localstack.cloud:4566",
...
},
"provisioningState": "Succeeded",
...
}

Enable Capture on the event hub:

Terminal window
STORAGE_ID=$(az storage account show \
--resource-group rg-eventhubs-demo \
--name stehcapturels \
--query id -o tsv)
az eventhubs eventhub update \
--resource-group rg-eventhubs-demo \
--namespace-name ehnsdoc42 \
--name orders-hub \
--enable-capture true \
--capture-interval 60 \
--capture-size-limit 10485760 \
--destination-name EventHubArchive.AzureBlockBlob \
--storage-account "$STORAGE_ID" \
--blob-container eventhub-capture \
--skip-empty-archives true
Output
{
"captureDescription": {
"destination": {
"blobContainer": "eventhub-capture",
"name": "EventHubArchive.AzureBlockBlob",
"storageAccountResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventhubs-demo/providers/Microsoft.Storage/storageAccounts/stehcapturels"
},
"enabled": true,
"encoding": "Avro",
"intervalInSeconds": 60,
"sizeLimitInBytes": 10485760,
"skipEmptyArchives": true
},
"name": "orders-hub",
...
}

Send a few more events, wait for the capture window to elapse (60 seconds here), and list the archives:

Terminal window
STORAGE_CONNECTION=$(az storage account show-connection-string \
--resource-group rg-eventhubs-demo \
--name stehcapturels \
--query connectionString -o tsv)
az storage blob list \
--container-name eventhub-capture \
--connection-string "$STORAGE_CONNECTION" \
--query "[].{name:name, bytes:properties.contentLength}" -o json
Output
[
{
"bytes": 605,
"name": "ehnsdoc42/orders-hub/0/2026/08/09/19/23/32.avro"
},
{
"bytes": 674,
"name": "ehnsdoc42/orders-hub/1/2026/08/09/19/23/32.avro"
},
{
"bytes": 605,
"name": "ehnsdoc42/orders-hub/2/2026/08/09/19/23/32.avro"
},
{
"bytes": 605,
"name": "ehnsdoc42/orders-hub/3/2026/08/09/19/23/32.avro"
}
]

The archives are Avro object-container files in Azure’s EventData record schema, one per partition and capture window. After each archive is written, the emulator raises the Microsoft.EventHub.CaptureFileCreated event through Event Grid system topics, so downstream automation such as an Azure Function can react to new archives.

The emulator includes the following core capabilities:

  • Multi-protocol data plane on a single event log: AMQP 1.0 (what the official azure-eventhub SDKs speak, including AMQP-over-WebSockets), a Kafka-compatible endpoint, the HTTP runtime API, and the legacy Atom-XML management API all read and write the same per-partition log, so an event sent over one protocol is readable over the others.
  • ARM control plane: CRUD for namespaces, event hubs, consumer groups, authorization rules and keys, network rule sets, schema groups, application groups, geo-disaster-recovery configurations, and dedicated clusters — with tier quotas enforced as in Azure (event hub counts, retention caps, partition limits, and the Basic-tier consumer-group restriction).
  • Event Hubs Capture: per-partition Avro archives written to emulated Blob Storage on time- or size-based windows, including skipEmptyArchives, and the Microsoft.EventHub.CaptureFileCreated system event raised through Event Grid.
  • Schema Registry: the data-plane API served on the namespace endpoint, with schema group CRUD, schema registration and versioning, lookup by content, and the tier quota on schema groups.
  • Checkpointing: the SDK’s event processor pattern works with the blob-backed checkpoint store against emulated Blob Storage.
  • Kafka-compatible endpoint: topics map to event hubs, Kafka offsets equal Event Hubs sequence numbers, and consumer-group offsets are stored broker-side; verified with kafka-python and confluent-kafka.
  • Emulator-ready connection strings: keys list returns connection strings that the Azure SDKs, Kafka clients, and IaC tools can use verbatim against the emulator.

The current version of the emulator does not support the following:

  • Credential verification: SAS tokens and JWTs are checked for the existence of the target entity, but signatures are not cryptographically verified. The Kafka endpoint listens in plaintext without SASL, whereas real Azure requires SASL_SSL.
  • Azure’s partition-key hash: the partition-key-to-partition mapping is a stable hash, so events with the same key land on the same partition, but the concrete partition ids differ from real Azure.
  • Kafka namespace isolation: Kafka topics resolve across all Kafka-enabled namespaces, and Kafka consumer-group offsets and producer ids are held in memory only.
  • Enforcement of throughput and network controls: throughput-unit throttling, application-group policies, network rule sets, private endpoints, and geo-disaster-recovery are stored and echoed as metadata, but not enforced — a geo-DR failover changes state without moving events.
  • Dedicated cluster hardware: clusters are metadata-level, and Azure’s 4-hour cluster deletion moratorium is intentionally skipped so local clean-up is immediate.
  • Receiving over HTTP: the HTTP runtime API is send-only, as in Azure; receiving requires AMQP or Kafka.
  • Persistence: entities and event data are held in memory and are lost when the emulator restarts. Recreate resources on startup via the CLI or IaC.

Explore the following samples to get started with Event Hubs on LocalStack:

OperationImplemented
Page 1 of 0
Was this page helpful?