Skip to content
Get Started for Free

Event Grid

Azure Event Grid is a fully managed event routing service that enables event-driven architectures using a publish-subscribe model. It supports custom topics for application events, system topics for Azure resource events, domains for multi-tenant scenarios, and namespaces for MQTT and CloudEvents pull delivery. Event Grid handles routing, filtering, and reliable delivery to multiple destination types. For more information, see What is Azure Event Grid?

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

This guide is designed for users new to Event Grid 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 Grid resources:

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

Create an Event Grid topic for publishing custom events:

Terminal window
az eventgrid topic create \
--resource-group rg-eventgrid-demo \
--name topic-orders \
--location westeurope
Output
{
"dataResidencyBoundary": "WithinGeopair",
"disableLocalAuth": false,
"endpoint": "https://topic-orders.azure.localhost.localstack.cloud:4566/api/events",
"extendedLocation": null,
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventgrid-demo/providers/Microsoft.EventGrid/topics/topic-orders",
"identity": null,
"inboundIpRules": null,
"inputSchema": "EventGridSchema",
"inputSchemaMapping": null,
"kind": null,
"location": "westeurope",
"metricResourceId": "6f4b8a01-41c7-45ec-bfc8-2c51978d9ed1",
"name": "topic-orders",
"privateEndpointConnections": null,
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled",
"resourceGroup": "rg-eventgrid-demo",
"sku": null,
"systemData": null,
"tags": null,
"type": "Microsoft.EventGrid/topics"
}

Get the topic endpoint and access key:

Terminal window
TOPIC_ENDPOINT=$(az eventgrid topic show \
--resource-group rg-eventgrid-demo \
--name topic-orders \
--query endpoint -o tsv)
TOPIC_KEY=$(az eventgrid topic key list \
--resource-group rg-eventgrid-demo \
--name topic-orders \
--query key1 -o tsv)

Create an event subscription with filtering

Section titled “Create an event subscription with filtering”

Create an event subscription that delivers events to a Storage Queue with event type and subject filtering:

Terminal window
az storage account create \
--resource-group rg-eventgrid-demo \
--name stegdemo83 \
--location westeurope \
--sku Standard_LRS \
--output none
az storage queue create \
--account-name stegdemo83 \
--name orders-queue \
--output none
STORAGE_ID=$(az storage account show \
--resource-group rg-eventgrid-demo \
--name stegdemo83 \
--query id -o tsv)
az eventgrid event-subscription create \
--source-resource-id "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventgrid-demo/providers/Microsoft.EventGrid/topics/topic-orders" \
--name orders-to-queue \
--endpoint-type storagequeue \
--endpoint "$STORAGE_ID/queueServices/default/queues/orders-queue" \
--included-event-types "OrderCreated" "OrderUpdated" \
--subject-begins-with "orders/" \
--event-delivery-schema CloudEventSchemaV1_0
Output
{
"deadLetterDestination": null,
"deadLetterWithResourceIdentity": null,
"deliveryWithResourceIdentity": null,
"destination": {
"endpointType": "StorageQueue",
"queueMessageTimeToLiveInSeconds": null,
"queueName": "orders-queue",
"resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventgrid-demo/providers/Microsoft.Storage/storageAccounts/stegdemo83"
},
"eventDeliverySchema": "CloudEventSchemaV1_0",
"expirationTimeUtc": null,
"filter": {
"advancedFilters": null,
"enableAdvancedFilteringOnArrays": null,
"includedEventTypes": [
"OrderCreated",
"OrderUpdated"
],
"isSubjectCaseSensitive": null,
"subjectBeginsWith": "orders/",
"subjectEndsWith": ""
},
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventgrid-demo/providers/Microsoft.EventGrid/topics/topic-orders/providers/Microsoft.EventGrid/eventSubscriptions/orders-to-queue",
"labels": null,
"name": "orders-to-queue",
"provisioningState": "Succeeded",
"resourceGroup": "rg-eventgrid-demo",
"retryPolicy": {
"eventTimeToLiveInMinutes": 1440,
"maxDeliveryAttempts": 30
},
"systemData": null,
"topic": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-eventgrid-demo/providers/microsoft.eventgrid/topics/topic-orders",
"type": "Microsoft.EventGrid/eventSubscriptions"
}

Publish an event to the custom topic:

Terminal window
curl -X POST "$TOPIC_ENDPOINT" \
-H "aeg-sas-key: $TOPIC_KEY" \
-H "Content-Type: application/json" \
-d '[{
"id": "1001",
"eventType": "OrderCreated",
"subject": "orders/1001",
"eventTime": "2026-09-28T10:00:00Z",
"data": {
"orderId": 1001,
"status": "created"
},
"dataVersion": "1.0"
}]'
Output
{}

Check that the event was delivered to the queue:

Terminal window
az storage message peek \
--account-name stegdemo83 \
--queue-name orders-queue \
--num-messages 1
Output
[
{
"content": "eyJpZCI6ICIxMDAxIiwgInNvdXJjZSI6ICIvc3Vic2NyaXB0aW9ucy8wMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAvcmVzb3VyY2VHcm91cHMvcmctZXZlbnRncmlkLWRlbW8vcHJvdmlkZXJzL01pY3Jvc29mdC5FdmVudEdyaWQvdG9waWNzL3RvcGljLW9yZGVycyIsICJzcGVjdmVyc2lvbiI6ICIxLjAiLCAidHlwZSI6ICJPcmRlckNyZWF0ZWQiLCAic3ViamVjdCI6ICJvcmRlcnMvMTAwMSIsICJ0aW1lIjogIjIwMjYtMDktMjhUMTA6MDA6MDBaIiwgImRhdGEiOiB7Im9yZGVySWQiOiAxMDAxLCAic3RhdHVzIjogImNyZWF0ZWQifX0=",
"dequeueCount": 0,
"expirationTime": "2026-10-06T15:51:59+00:00",
"id": "a7523087-3ae1-421a-a21e-d72a95f8c7a4",
"insertionTime": "2026-09-29T15:51:59+00:00",
"popReceipt": null,
"timeNextVisible": null
}
]

Create an Event Grid namespace with a topic and queue subscription for CloudEvents pull delivery:

Terminal window
az eventgrid namespace create \
--resource-group rg-eventgrid-demo \
--name egns-demo \
--location westeurope
az eventgrid namespace topic create \
--resource-group rg-eventgrid-demo \
--namespace-name egns-demo \
--name orders
az eventgrid namespace topic event-subscription create \
--resource-group rg-eventgrid-demo \
--namespace-name egns-demo \
--topic-name orders \
--name orders-pull \
--delivery-configuration "{deliveryMode:Queue,queue:{receiveLockDurationInSeconds:60,maxDeliveryCount:4,eventTimeToLive:P1D}}" \
--event-delivery-schema CloudEventSchemaV1_0

Publish and receive events using the namespace data plane endpoint:

Terminal window
NAMESPACE_ENDPOINT=$(az eventgrid namespace show \
--resource-group rg-eventgrid-demo \
--name egns-demo \
--query topicsConfiguration.hostname -o tsv)
NAMESPACE_KEY=$(az eventgrid namespace list-key \
--resource-group rg-eventgrid-demo \
--namespace-name egns-demo \
--query key1 -o tsv)
# Publish a CloudEvent
curl -X POST "https://$NAMESPACE_ENDPOINT/topics/orders:publish?api-version=2023-06-01-preview" \
-H "aeg-sas-key: $NAMESPACE_KEY" \
-H "Content-Type: application/cloudevents+json" \
-d '{
"specversion": "1.0",
"id": "2001",
"type": "OrderCreated",
"source": "/myapp/orders",
"time": "2026-09-28T10:00:00Z",
"data": {
"orderId": 2001,
"status": "created"
}
}'
# Receive events from the queue subscription
curl -X POST "https://$NAMESPACE_ENDPOINT/topics/orders/eventsubscriptions/orders-pull:receive?api-version=2023-06-01-preview&maxEvents=1" \
-H "aeg-sas-key: $NAMESPACE_KEY"

The receive call returns the event together with the lock token to acknowledge, reject, or release it with:

Output
{"value": [{"brokerProperties": {"lockToken": "84238b76-4baf-42b4-90ed-563993b9b161", "deliveryCount": 1}, "event": {"id": "2001", "source": "/myapp/orders", "data": {"orderId": 2001, "status": "created"}, "type": "OrderCreated", "time": "2026-09-28T10:00:00Z", "specversion": "1.0"}}]}

The emulator includes the following core capabilities:

  • Idempotent resource management: Repeated create-or-update operations for topics, domains, system topics, namespaces, namespace topics, and topic and system topic event subscriptions update in place without resetting access keys, child resources, or subscriptions. A create-or-update of an existing namespace topic event subscription, including az eventgrid namespace topic event-subscription update, replaces it and discards the events not yet acknowledged; only a PATCH updates it in place.
  • Configuration storage: Topics, domains, and subscriptions store and return inputSchema, eventDeliverySchema, retryPolicy, publicNetworkAccess, disableLocalAuth, inboundIpRules, minimumTlsVersionAllowed, dataResidencyBoundary, and identity. inputSchemaMapping is not stored, so custom input schemas are not mapped.
  • Resource hierarchy: Deleting a topic, system topic, or domain automatically deletes its child resources. Namespace resource updates via PATCH are supported.
  • Access key management: Topics, domains, and namespaces support key regeneration with key1 and key2.

Event subscriptions apply filters before delivery:

  • Event type filtering: Only events with types in includedEventTypes are delivered.
  • Subject filtering: subjectBeginsWith and subjectEndsWith filters with optional case sensitivity via isSubjectCaseSensitive.
  • Advanced filters: All 19 operators are evaluated: the numeric operators, including NumberInRange and NumberNotInRange, BoolEquals, the string operators, IsNullOrUndefined, and IsNotNull. String comparisons are case-insensitive, and an array-valued key is compared only when enableAdvancedFilteringOnArrays is true.

Event subscriptions support the following destination types:

  • Storage Queue: Events delivered as base64-encoded messages, one event per message, with configurable queueMessageTimeToLiveInSeconds.
  • Service Bus Queue: Events delivered with aeg-* application properties and the configured delivery schema.
  • Service Bus Topic: Events delivered to Service Bus topics with aeg-* application properties.
  • Event Hubs: One event per Event Grid event, whose body is a one-element JSON array.
  • WebHook: Events delivered via HTTP POST with aeg-* headers in a background thread.
  • When a subscription’s eventDeliverySchema is set to CloudEventSchemaV1_0, Event Grid schema events are automatically converted to CloudEvents 1.0 format before delivery.

The namespace data plane supports:

  • CloudEvents publishing: Accepts structured single-event, batch, and binary-mode CloudEvents with validation of required attributes.
  • Queue subscriptions: Receive operations honour receiveLockDurationInSeconds and maxDeliveryCount, which are read again on every receive. eventTimeToLive is applied to each event when it is published.
  • Lock management: Every delivery gets a fresh lock token. Operations support acknowledge, reject, release with configurable releaseDelayInSeconds, and renewLock.
  • Validation: maxEvents defaults to 1 (range 1-100) and maxWaitTime is validated (range 10-120 seconds).

System topics can be created and subscribed to, but the only system event the emulator raises is Microsoft.EventHub.CaptureFileCreated, which Event Hubs Capture publishes when it writes an archive. It reaches the system topics whose source is the Event Hubs namespace.

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

  • No retries or dead-lettering: Push delivery makes a single attempt. Failed deliveries are not retried and are not written to the dead-letter destination. In namespace pull delivery, rejected events and events that exceed maxDeliveryCount are dropped.
  • No webhook validation handshake: WebHook destinations receive neither the SubscriptionValidation handshake nor the CloudEvents OPTIONS request that real Azure sends before activating the subscription.
  • Single-attempt delivery: Retry policies and exponential backoff are stored but not enforced.
  • Unsupported destinations: AzureFunction, HybridConnection, MonitorAlert, and NamespaceTopic destinations are accepted, but their events are logged and dropped.
  • No delivery properties or managed identity: Custom delivery properties (static and dynamic headers) and managed-identity delivery (deliveryWithResourceIdentity) are ignored.
  • No domain publishing: Publishing events to domain endpoints is not supported. Use custom topics instead.
  • No automatic system topic creation: System topics must be created explicitly. Azure automatically creates system topics when you subscribe to resource events, but the emulator does not.
  • Resource group scoping: Stores are keyed by name within a subscription and region, so the same resource name in two resource groups may collide.
  • No domain subscriptions: Domain and domain topic event subscriptions are not supported. An event subscription created at a subscription or resource group scope is stored but receives no events.
  • Namespace subscriptions deliver every event: Namespace topic event subscriptions ignore filtersConfiguration, so each receives every event published to its topic, and the Push delivery mode delivers nothing.
  • Access keys are not checked: Publishing to a custom topic does not check the aeg-sas-key header, and the namespace data plane is protected only when RBAC enforcement is enabled.
  • No partner events: Partner namespaces, partner topics, partner registrations, and channels are not supported.
  • No extension topics: Extension topics are not available.
  • No MQTT broker: MQTT clients, client groups, permission bindings, CA certificates, and topic spaces are not supported.
  • Where Microsoft Learn does not specify a behavior, filtering is approximated: includedEventTypes is compared case-insensitively, keys after data. are case-sensitive, a null value counts as missing, and an array-valued key contributes no values unless enableAdvancedFilteringOnArrays is true.

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

75 of 170 operations implemented

Operation ▲Implemented ▼
Page 1 of 0
Was this page helpful?