The azure-native:app:DaprSubscription resource, part of the Pulumi Azure Native provider, connects a Dapr pub/sub component to a topic and defines how messages are routed to Container Apps. This guide focuses on three capabilities: basic topic subscription with single-route delivery, content-based routing with conditional rules, and bulk message delivery and application scoping.
Dapr subscriptions belong to a Container Apps managed environment and require a configured pub/sub component and deployed container apps. The examples are intentionally small. Combine them with your own environment, pub/sub components, and application deployments.
Subscribe to a topic with a single route
Most subscriptions connect an environment to a pub/sub topic and route all messages to one application endpoint.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const daprSubscription = new azure_native.app.DaprSubscription("daprSubscription", {
environmentName: "myenvironment",
name: "mysubscription",
pubsubName: "mypubsubcomponent",
resourceGroupName: "examplerg",
routes: {
"default": "/products",
},
topic: "inventory",
});
import pulumi
import pulumi_azure_native as azure_native
dapr_subscription = azure_native.app.DaprSubscription("daprSubscription",
environment_name="myenvironment",
name="mysubscription",
pubsub_name="mypubsubcomponent",
resource_group_name="examplerg",
routes={
"default": "/products",
},
topic="inventory")
package main
import (
app "github.com/pulumi/pulumi-azure-native-sdk/app/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := app.NewDaprSubscription(ctx, "daprSubscription", &app.DaprSubscriptionArgs{
EnvironmentName: pulumi.String("myenvironment"),
Name: pulumi.String("mysubscription"),
PubsubName: pulumi.String("mypubsubcomponent"),
ResourceGroupName: pulumi.String("examplerg"),
Routes: &app.DaprSubscriptionRoutesArgs{
Default: pulumi.String("/products"),
},
Topic: pulumi.String("inventory"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var daprSubscription = new AzureNative.App.DaprSubscription("daprSubscription", new()
{
EnvironmentName = "myenvironment",
Name = "mysubscription",
PubsubName = "mypubsubcomponent",
ResourceGroupName = "examplerg",
Routes = new AzureNative.App.Inputs.DaprSubscriptionRoutesArgs
{
Default = "/products",
},
Topic = "inventory",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.app.DaprSubscription;
import com.pulumi.azurenative.app.DaprSubscriptionArgs;
import com.pulumi.azurenative.app.inputs.DaprSubscriptionRoutesArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var daprSubscription = new DaprSubscription("daprSubscription", DaprSubscriptionArgs.builder()
.environmentName("myenvironment")
.name("mysubscription")
.pubsubName("mypubsubcomponent")
.resourceGroupName("examplerg")
.routes(DaprSubscriptionRoutesArgs.builder()
.default_("/products")
.build())
.topic("inventory")
.build());
}
}
resources:
daprSubscription:
type: azure-native:app:DaprSubscription
properties:
environmentName: myenvironment
name: mysubscription
pubsubName: mypubsubcomponent
resourceGroupName: examplerg
routes:
default: /products
topic: inventory
The pubsubName references a Dapr component configured in your Container Apps environment. The topic property specifies which pub/sub topic to subscribe to. The routes.default property sets the HTTP path where your container app receives messages; Dapr posts each message to this endpoint.
Route messages by content with conditional rules
When multiple event types share a topic, routing rules direct messages to specialized handlers based on content.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const daprSubscription = new azure_native.app.DaprSubscription("daprSubscription", {
environmentName: "myenvironment",
metadata: {
foo: "bar",
hello: "world",
},
name: "mysubscription",
pubsubName: "mypubsubcomponent",
resourceGroupName: "examplerg",
routes: {
"default": "/products",
rules: [
{
match: "event.type == 'widget'",
path: "/widgets",
},
{
match: "event.type == 'gadget'",
path: "/gadgets",
},
],
},
topic: "inventory",
});
import pulumi
import pulumi_azure_native as azure_native
dapr_subscription = azure_native.app.DaprSubscription("daprSubscription",
environment_name="myenvironment",
metadata={
"foo": "bar",
"hello": "world",
},
name="mysubscription",
pubsub_name="mypubsubcomponent",
resource_group_name="examplerg",
routes={
"default": "/products",
"rules": [
{
"match": "event.type == 'widget'",
"path": "/widgets",
},
{
"match": "event.type == 'gadget'",
"path": "/gadgets",
},
],
},
topic="inventory")
package main
import (
app "github.com/pulumi/pulumi-azure-native-sdk/app/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := app.NewDaprSubscription(ctx, "daprSubscription", &app.DaprSubscriptionArgs{
EnvironmentName: pulumi.String("myenvironment"),
Metadata: pulumi.StringMap{
"foo": pulumi.String("bar"),
"hello": pulumi.String("world"),
},
Name: pulumi.String("mysubscription"),
PubsubName: pulumi.String("mypubsubcomponent"),
ResourceGroupName: pulumi.String("examplerg"),
Routes: &app.DaprSubscriptionRoutesArgs{
Default: pulumi.String("/products"),
Rules: app.DaprSubscriptionRouteRuleArray{
&app.DaprSubscriptionRouteRuleArgs{
Match: pulumi.String("event.type == 'widget'"),
Path: pulumi.String("/widgets"),
},
&app.DaprSubscriptionRouteRuleArgs{
Match: pulumi.String("event.type == 'gadget'"),
Path: pulumi.String("/gadgets"),
},
},
},
Topic: pulumi.String("inventory"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var daprSubscription = new AzureNative.App.DaprSubscription("daprSubscription", new()
{
EnvironmentName = "myenvironment",
Metadata =
{
{ "foo", "bar" },
{ "hello", "world" },
},
Name = "mysubscription",
PubsubName = "mypubsubcomponent",
ResourceGroupName = "examplerg",
Routes = new AzureNative.App.Inputs.DaprSubscriptionRoutesArgs
{
Default = "/products",
Rules = new[]
{
new AzureNative.App.Inputs.DaprSubscriptionRouteRuleArgs
{
Match = "event.type == 'widget'",
Path = "/widgets",
},
new AzureNative.App.Inputs.DaprSubscriptionRouteRuleArgs
{
Match = "event.type == 'gadget'",
Path = "/gadgets",
},
},
},
Topic = "inventory",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.app.DaprSubscription;
import com.pulumi.azurenative.app.DaprSubscriptionArgs;
import com.pulumi.azurenative.app.inputs.DaprSubscriptionRoutesArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var daprSubscription = new DaprSubscription("daprSubscription", DaprSubscriptionArgs.builder()
.environmentName("myenvironment")
.metadata(Map.ofEntries(
Map.entry("foo", "bar"),
Map.entry("hello", "world")
))
.name("mysubscription")
.pubsubName("mypubsubcomponent")
.resourceGroupName("examplerg")
.routes(DaprSubscriptionRoutesArgs.builder()
.default_("/products")
.rules(
DaprSubscriptionRouteRuleArgs.builder()
.match("event.type == 'widget'")
.path("/widgets")
.build(),
DaprSubscriptionRouteRuleArgs.builder()
.match("event.type == 'gadget'")
.path("/gadgets")
.build())
.build())
.topic("inventory")
.build());
}
}
resources:
daprSubscription:
type: azure-native:app:DaprSubscription
properties:
environmentName: myenvironment
metadata:
foo: bar
hello: world
name: mysubscription
pubsubName: mypubsubcomponent
resourceGroupName: examplerg
routes:
default: /products
rules:
- match: event.type == 'widget'
path: /widgets
- match: event.type == 'gadget'
path: /gadgets
topic: inventory
The routes.rules array defines conditional routing: each rule has a match expression that evaluates message properties and a path for matching messages. Messages that don’t match any rule fall back to routes.default. The metadata property passes key-value pairs to the underlying pub/sub component, configuring broker-specific behavior.
Optimize throughput with bulk delivery and scopes
High-volume subscriptions batch messages into single requests to reduce network overhead, and scopes control which apps receive messages.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const daprSubscription = new azure_native.app.DaprSubscription("daprSubscription", {
bulkSubscribe: {
enabled: true,
maxAwaitDurationMs: 500,
maxMessagesCount: 123,
},
environmentName: "myenvironment",
name: "mysubscription",
pubsubName: "mypubsubcomponent",
resourceGroupName: "examplerg",
routes: {
"default": "/products",
},
scopes: [
"warehouseapp",
"customersupportapp",
],
topic: "inventory",
});
import pulumi
import pulumi_azure_native as azure_native
dapr_subscription = azure_native.app.DaprSubscription("daprSubscription",
bulk_subscribe={
"enabled": True,
"max_await_duration_ms": 500,
"max_messages_count": 123,
},
environment_name="myenvironment",
name="mysubscription",
pubsub_name="mypubsubcomponent",
resource_group_name="examplerg",
routes={
"default": "/products",
},
scopes=[
"warehouseapp",
"customersupportapp",
],
topic="inventory")
package main
import (
app "github.com/pulumi/pulumi-azure-native-sdk/app/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := app.NewDaprSubscription(ctx, "daprSubscription", &app.DaprSubscriptionArgs{
BulkSubscribe: &app.DaprSubscriptionBulkSubscribeOptionsArgs{
Enabled: pulumi.Bool(true),
MaxAwaitDurationMs: pulumi.Int(500),
MaxMessagesCount: pulumi.Int(123),
},
EnvironmentName: pulumi.String("myenvironment"),
Name: pulumi.String("mysubscription"),
PubsubName: pulumi.String("mypubsubcomponent"),
ResourceGroupName: pulumi.String("examplerg"),
Routes: &app.DaprSubscriptionRoutesArgs{
Default: pulumi.String("/products"),
},
Scopes: pulumi.StringArray{
pulumi.String("warehouseapp"),
pulumi.String("customersupportapp"),
},
Topic: pulumi.String("inventory"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var daprSubscription = new AzureNative.App.DaprSubscription("daprSubscription", new()
{
BulkSubscribe = new AzureNative.App.Inputs.DaprSubscriptionBulkSubscribeOptionsArgs
{
Enabled = true,
MaxAwaitDurationMs = 500,
MaxMessagesCount = 123,
},
EnvironmentName = "myenvironment",
Name = "mysubscription",
PubsubName = "mypubsubcomponent",
ResourceGroupName = "examplerg",
Routes = new AzureNative.App.Inputs.DaprSubscriptionRoutesArgs
{
Default = "/products",
},
Scopes = new[]
{
"warehouseapp",
"customersupportapp",
},
Topic = "inventory",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.app.DaprSubscription;
import com.pulumi.azurenative.app.DaprSubscriptionArgs;
import com.pulumi.azurenative.app.inputs.DaprSubscriptionBulkSubscribeOptionsArgs;
import com.pulumi.azurenative.app.inputs.DaprSubscriptionRoutesArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var daprSubscription = new DaprSubscription("daprSubscription", DaprSubscriptionArgs.builder()
.bulkSubscribe(DaprSubscriptionBulkSubscribeOptionsArgs.builder()
.enabled(true)
.maxAwaitDurationMs(500)
.maxMessagesCount(123)
.build())
.environmentName("myenvironment")
.name("mysubscription")
.pubsubName("mypubsubcomponent")
.resourceGroupName("examplerg")
.routes(DaprSubscriptionRoutesArgs.builder()
.default_("/products")
.build())
.scopes(
"warehouseapp",
"customersupportapp")
.topic("inventory")
.build());
}
}
resources:
daprSubscription:
type: azure-native:app:DaprSubscription
properties:
bulkSubscribe:
enabled: true
maxAwaitDurationMs: 500
maxMessagesCount: 123
environmentName: myenvironment
name: mysubscription
pubsubName: mypubsubcomponent
resourceGroupName: examplerg
routes:
default: /products
scopes:
- warehouseapp
- customersupportapp
topic: inventory
The bulkSubscribe configuration enables batching: maxMessagesCount sets the batch size, and maxAwaitDurationMs controls how long Dapr waits to fill a batch before delivering. The scopes array restricts message delivery to specific container apps by name, preventing unauthorized apps from receiving messages.
Beyond these examples
These snippets focus on specific subscription-level features: topic subscription and message routing, bulk delivery optimization, and application scoping and metadata. They’re intentionally minimal rather than full event-driven architectures.
The examples reference pre-existing infrastructure such as Container Apps managed environments, Dapr pub/sub component configurations, and container apps for message delivery. They focus on configuring the subscription rather than provisioning the surrounding infrastructure.
To keep things focused, common subscription patterns are omitted, including:
- Dead letter topic configuration (deadLetterTopic)
- Advanced route rule expressions and operators
- Retry policies and error handling
- Multiple pub/sub components in one environment
These omissions are intentional: the goal is to illustrate how each subscription feature is wired, not provide drop-in messaging modules. See the DaprSubscription resource reference for all available configuration options.
Let's configure Azure Dapr PubSub Event Subscriptions
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Setup
name (subscription name), environmentName (Managed Environment name), resourceGroupName, pubsubName (Dapr PubSub component), and topic (topic name to subscribe to).name, environmentName, and resourceGroupName properties are immutable. Changing any of these requires destroying and recreating the resource.metadata property with key-value pairs, such as {"foo": "bar", "hello": "world"}.Event Routing
routes with a default path (e.g., /products) for all events. For conditional routing, add rules with match expressions and specific path values, like "match": "event.type == 'widget'" routing to "/widgets".default route handles all events that don’t match any rules. Route rules use match expressions to conditionally route specific event types to different paths.Performance & Optimization
bulkSubscribe with enabled: true, maxAwaitDurationMs (e.g., 500), and maxMessagesCount (e.g., 123) to process multiple messages in batches.scopes array to specify app names (e.g., ["warehouseapp", "customersupportapp"]) that should receive events from this subscription.Error Handling
deadLetterTopic property to specify a topic name where failed messages should be sent.Resource Management
pulumi import azure-native:app:DaprSubscription <name> /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.App/managedEnvironments/{environmentName}/daprSubscriptions/{name}.