Workflow Concurrency Limits

Configure concurrency limits for Dapr Workflows to control how many workflows and activities run simultaneously.

Dapr provides concurrency limits for workflows and activities at two levels:

  • Per-sidecar limits control how many workflows or activities a single Dapr instance can execute concurrently.
  • Global limits control the total across all replicas, enforced by the scheduler.

Both levels can be configured independently and work together. Per-sidecar limits protect individual instances from resource exhaustion. Global limits enforce cluster-wide capacity constraints, for example, to respect rate limits on downstream services.

Per-sidecar limits

Per-sidecar limits restrict concurrency within a single Dapr sidecar. If you have 10 replicas with a per-sidecar limit of 100, the effective cluster-wide capacity is up to 1000.

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  workflow:
    maxConcurrentWorkflowInvocations: 100
    maxConcurrentActivityInvocations: 1000
PropertyTypeDescription
maxConcurrentWorkflowInvocationsint32Max concurrent workflow executions per sidecar. Default: unlimited.
maxConcurrentActivityInvocationsint32Max concurrent activity executions per sidecar. Default: unlimited.

These limits do not distinguish between different workflow or activity names. They apply to all workflows and activities running in the sidecar.

Global limits

Global limits enforce a maximum across all replicas of your application. The Dapr scheduler divides the limit among its instances and holds back triggers when the limit is reached, dispatching them as capacity becomes available.

All workflows or all activities

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  workflow:
    globalMaxConcurrentWorkflowInvocations: 50
    globalMaxConcurrentActivityInvocations: 200
PropertyTypeDescription
globalMaxConcurrentWorkflowInvocationsint32Max concurrent workflow executions across all replicas. Default: unlimited.
globalMaxConcurrentActivityInvocationsint32Max concurrent activity executions across all replicas. Default: unlimited.

Per-name limits

You can set concurrency limits for specific workflow or activity names. This is useful when certain workflows or activities call rate-limited external services.

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  workflow:
    globalMaxConcurrentActivityInvocations: 200
    activityConcurrencyLimits:
      - name: SendEmail
        maxConcurrent: 5
      - name: CallPaymentAPI
        maxConcurrent: 10
    workflowConcurrencyLimits:
      - name: OrderProcess
        maxConcurrent: 20
PropertyTypeDescription
activityConcurrencyLimitsarrayPer-activity-name concurrency limits.
workflowConcurrencyLimitsarrayPer-workflow-name concurrency limits.
activityConcurrencyLimits[].namestringActivity name to limit.
activityConcurrencyLimits[].maxConcurrentint32Max concurrent executions across all replicas for this activity.
workflowConcurrencyLimits[].namestringWorkflow name to limit.
workflowConcurrencyLimits[].maxConcurrentint32Max concurrent executions across all replicas for this workflow.

A trigger must satisfy all applicable limits. For example, if globalMaxConcurrentActivityInvocations is 200 and SendEmail has a per-name limit of 5, then at most 5 SendEmail activities can run, and all activities combined cannot exceed 200.

How the levels interact

Limit typeScopeEnforcement pointEffect of scaling replicas
Per-sidecarSingle instanceDapr sidecarEffective max = limit x replicas
Global (type)All replicasSchedulerFixed total regardless of replicas
Global (per-name)All replicasSchedulerFixed total regardless of replicas

When both per-sidecar and global limits are configured, both apply. The global limit prevents the cluster-wide total from exceeding the configured value, while the per-sidecar limit prevents any single instance from consuming too much local resources.

How global limits work with multiple scheduler replicas

The scheduler divides global limits evenly among its instances using floor division. With a global limit of 100 and 3 scheduler replicas, each scheduler enforces a local limit of 33, for an effective cluster max of 99. This ensures the configured limit is never exceeded.

Comparison with other rate limiting options

Dapr provides several ways to control concurrency and rate limiting:

ApproachWhat it controlsGranularityScope
Workflow concurrency limitsWorkflow and activity executionsPer-type or per-namePer-sidecar or global
app-max-concurrencyAll requests and events to an appAll trafficPer-sidecar
Rate limit middlewareHTTP requests per secondPer remote IPPer-sidecar
Last modified April 9, 2026: Review comments (5882fb986)