The azure-native:app:DaprSubscription resource, part of the Pulumi Azure Native provider, defines a Dapr pub/sub subscription within a Container Apps environment: which topic to subscribe to, how to route events, and which applications can receive them. This guide focuses on three capabilities: event routing (default and conditional), bulk message delivery, and application scoping.
Dapr subscriptions connect to pub/sub components configured in a Container Apps managed environment and may reference deployed container apps for scoping. The examples are intentionally small. Combine them with your own environment, pub/sub components, and application deployments.
Subscribe to a topic with a default route
Most subscriptions connect an environment to a pub/sub topic and route all events to a single 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 specifies which pub/sub topic to subscribe to. The routes.default property sets the HTTP path where your application receives events; Dapr delivers all messages from the topic to this endpoint.
Route events conditionally with match expressions
Applications often route different event types to specialized handlers rather than processing everything through one 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",
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 based on event properties. Each rule has a match expression (using Common Expression Language syntax) and a path. Dapr evaluates rules in order; events matching “event.type == ‘widget’” go to “/widgets”, while “gadget” events go to “/gadgets”. Unmatched events fall back to the default route. The metadata property passes key-value pairs to the underlying pub/sub component for broker-specific configuration.
Optimize throughput with bulk subscribe and scopes
High-volume subscriptions benefit from bulk message delivery to reduce network overhead. Scopes restrict which applications can receive events.
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 batch delivery. Dapr waits up to maxAwaitDurationMs (500 milliseconds) or until maxMessagesCount (123 messages) accumulates before delivering a batch to your application. The scopes array limits subscription visibility to specific apps; only “warehouseapp” and “customersupportapp” receive events from this subscription, even if other apps in the environment subscribe to the same topic.
Beyond these examples
These snippets focus on specific subscription-level features: topic routing (default and conditional), bulk message delivery, and application scoping. 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 referenced in scopes. 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)
- Custom metadata for pub/sub components
- Error handling and retry policies
These omissions are intentional: the goal is to illustrate how each subscription feature is wired, not provide drop-in event processing 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, environmentName, and resourceGroupName properties are immutable. Changing any of these requires replacing the resource.environmentName, name, pubsubName, resourceGroupName, topic, and a routes object with at least a default path.pubsubName property to the name of your Dapr PubSub component (e.g., mypubsubcomponent).Event Routing
routes.default with the path where events should be delivered (e.g., /products). This handles all events that don’t match specific rules.routes.rules with match expressions and paths. For example, match: "event.type == 'widget'" with path: "/widgets" routes widget events to the /widgets endpoint.routes.default path, which acts as a fallback for unmatched events.deadLetterTopic property to specify a topic name where failed events should be sent.Advanced Features
bulkSubscribe with enabled: true. You can also set maxMessagesCount (e.g., 123) and maxAwaitDurationMs (e.g., 500) to control batch size and timing.scopes array to list app names (e.g., ["warehouseapp", "customersupportapp"]). Only these apps will receive events from the subscription.metadata object to pass key-value pairs (e.g., {"foo": "bar", "hello": "world"}).