Dapr Workflow with Spring Boot
Build stateful, long-running, reliable workflows using the Dapr Workflow Spring Boot integration with Catalyst. The Dapr Workflow Spring Boot integration provides a powerful way to orchestrate complex business processes from within your Spring Boot applications.
Resources
- Dapr Java SDK GitHub
- Dapr Java SDK Maven Central
- Dapr Workflow Documentation
- Dapr Workflows and Spring - Baeldung
Prerequisites:
- JDK 21+ (Download)
- Maven 3.x or Gradle 6.x
- Dapr Spring Boot Starter
Create a Spring Boot project
If you don't already have a Spring Boot application, create one by visiting https://start.spring.io.

In the dependencies selector, select Spring Web and Spring Boot Actuator and click Generate.
This will download a Zip file that you need to unzip to start coding your Spring Boot application.
Add the Dapr Spring Boot Starter
Open the pom.xml (or build.gradle) file and add the Dapr Spring Boot Starter dependency. To find the latest version of the Dapr Spring Boot Starter check this link to Maven central.
Maven
Add the following dependency to your pom.xml:
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-boot-starter</artifactId>
<version>1.17.x</version>
</dependency>
Gradle
Add the following dependency to your build.gradle:
dependencies {
implementation 'io.dapr.spring:dapr-spring-boot-starter:1.xx.x'
}
Enable Dapr Workflows
For workflows to be discovered and registered to the workflow runtime, add the @EnableDaprWorkflows annotation to the Spring Boot application class.
package com.example.demo;
import io.dapr.spring.workflows.config.EnableDaprWorkflows;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDaprWorkflows
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
When the application starts, the @EnableDaprWorkflows annotation scans the classpath to look for Workflow and WorkflowActivity implementations and automatically registers them.
Project structure
After completing the following sections, your project will have this structure:
src/main/java/com/example/demo/
├── DemoApplication.java
├── SimpleWorkflow.java
├── FirstActivity.java
└── DemoRestController.java
src/test/java/com/example/demo/
└── TestDemoApplication.java (Testcontainers config)
Open with your favorite IDE and let's create your first workflow.
Create your first workflow
To create a workflow, create a class that implements the Workflow interface.
package com.example.demo;
import io.dapr.workflows.Workflow;
import io.dapr.workflows.WorkflowStub;
import org.springframework.stereotype.Component;
@Component
public class SimpleWorkflow implements Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
String instanceId = ctx.getInstanceId();
// <YOUR WORKFLOW LOGIC GOES HERE>
ctx.complete("Workflow completed");
};
}
}
You can have as many workflows as you want inside your Spring Boot projects.
Notice: Use the Spring @Component to make sure that the workflow definition is a managed Spring bean.
Once you have your workflow class, the next step is to implement your workflow logic. This can include:
- Calling activities: by using the
ctx.callActivity(...)method we can build durable integrations with other systems. - Waiting for external events: by using the
ctx.waitForExternalEvent(...)method the workflow will wait for events coming from outside your application. - Creating timers: the application can schedule timers to resume the workflow execution at a specific point in time in the future.
- Making logical choices: using Java constructs (if/switch statements) you can define multiple workflow branches and their behavior.
- Calling Child Workflows: compose complex scenarios by creating parent/child relationships across workflow definitions.
Let's expand the workflow definition to call an activity.
@Override
public WorkflowStub create() {
return ctx -> {
String instanceId = ctx.getInstanceId();
ctx.getLogger().info("> Workflow started {}", instanceId);
ctx.callActivity(FirstActivity.class.getName()).await();
// <MORE WORKFLOW LOGIC GOES HERE>
ctx.complete("Workflow completed");
};
}
Two lines are added to the workflow definition.
The first one uses ctx.getLogger().info() to log the workflow instance id. This is useful to troubleshoot workflow instance executions.
The next line calls a new activity called FirstActivity.
Create a workflow activity
Workflow activities give you the perfect place to call other services to build complex workflow orchestrations.
Let's create the FirstActivity that our workflow calls:
package com.example.demo;
import io.dapr.workflows.WorkflowActivity;
import io.dapr.workflows.WorkflowActivityContext;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
@Component
public class FirstActivity implements WorkflowActivity {
private Logger logger = org.slf4j.LoggerFactory.getLogger(FirstActivity.class);
@Override
public Object run(WorkflowActivityContext ctx) {
logger.info("Executing the First activity.");
return null;
}
}
You can create new workflow activities by implementing the WorkflowActivity interface.
Inside the Object run(WorkflowActivityContext ctx) you can implement business logic to integrate with other systems.
Activities will be called by workflow definitions and can be reused by multiple workflows.
Start workflow instances from a REST endpoint
Now you need a way to start workflow instances from your Spring Boot application. One way to do this is to create a @RestController that you can invoke from a user interface or another application.
package com.example.demo;
import io.dapr.workflows.client.DaprWorkflowClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoRestController {
@Autowired
private DaprWorkflowClient daprWorkflowClient;
@PostMapping("/start")
public String start() {
return daprWorkflowClient.scheduleNewWorkflow(SimpleWorkflow.class);
}
}
This is a minimal implementation with a single REST endpoint. When a POST request is sent to this endpoint it will schedule a new workflow instance.
The DaprWorkflowClient is injected (@Autowired) to use the scheduleNewWorkflow() method to start new instances of the SimpleWorkflow.
Now you have a complete workflow application that you can run locally.
Run locally with Testcontainers
To run Dapr Workflow applications in production, you need to install Dapr into a Kubernetes cluster. To speed up the inner development loop, you can run everything locally using the Dapr and Testcontainers integration.
To use this functionality you need to add the following dependency to the application with test scope.
Maven
Add the following dependency to pom.xml:
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-boot-starter-test</artifactId>
<version>1.xx.x</version>
<scope>test</scope>
</dependency>
Gradle
Add the following dependency to build.gradle:
dependencies {
test 'io.dapr.spring:dapr-spring-boot-starter-test:1.xx.x'
}
Once you have this test dependency, create a @TestConfiguration class that starts the Dapr container alongside your Spring Boot application.
package com.example.demo;
import io.dapr.spring.boot.testcontainers.DaprContainer;
import io.dapr.testcontainers.Component;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import java.util.Map;
@TestConfiguration(proxyBeanMethods = false)
public class TestDemoApplication {
private static final String daprImage = "daprio/daprd:latest";
@Bean
Network network() {
return Network.newNetwork();
}
@Bean
@ServiceConnection
DaprContainer daprContainer(Network network, GenericContainer<?> otelCollectorContainer) {
return new DaprContainer(daprImage)
.withNetwork(network)
.withAppName("workflow-app-dapr")
.withAppPort(8080)
.withComponent(new Component("kvstore", "state.in-memory", "v1",
Map.of("actorStateStore", "true")))
.withAppChannelAddress("host.testcontainers.internal")
.withAppHealthCheckPath("/actuator/health")
.dependsOn(otelCollectorContainer);
}
}
With this test configuration, whenever you start your Spring Boot application in test mode, Dapr will start automatically for local development.
To run in development mode use the following Maven goal:
mvn spring-boot:test-run
Creating new workflow instances
Now that the application is up and running, you can start a new workflow instance by calling the /start endpoint.
Let's use cURL to send a POST request to /start:
curl -X POST localhost:8080/start
Every time we send a POST request a new workflow instance will be started.
Check the following examples that contain the full source code described above:
Monitor with the Diagrid Dashboard
Once you are starting workflow instances, you can access the Diagrid Dev Dashboard to monitor your workflow executions.
The Diagrid Dev Dashboard is automatically set up by Testcontainers and started right beside the application.
To access the dashboard, look at the logs to find the URL:
Container ghcr.io/diagridio/diagrid-dashboard:0.0.1 started in PT0.393789S
Dapr Workflow Dashboard container started.
Access the Dashboard at: http://localhost:58653
Use the listed URL to access the Diagrid Workflows Dashboard.

Run against Diagrid Catalyst
Once you have written your workflows and tested them locally, you can run against the Diagrid Catalyst SaaS service in the cloud.
To do this, download the Diagrid CLI and use it in conjunction with Maven to start your application.
Once you have the diagrid cli you will need to login to your Diagrid account by running the following command:
diagrid login
If you don't have an account, you can create one here.
To run the application locally against Catalyst, use the diagrid dev run command in conjunction with mvn spring-boot:run.
This will start the Spring Boot application and connect to the Catalyst Workflow Engine to run your workflows.
diagrid dev run --project spring-boot --app-id workflows --app-port 8080 -- mvn spring-boot:run
The first part of the command will create the spring-boot project in Catalyst along with the workflows app-id.
Once this is done, Maven will take care of starting our Spring Boot application.
You should see in your terminal the application starting:
diagrid dev run --project spring-boot --app-id workflows --app-port 8080 -- mvn spring-boot:run
Running App ID "workflows" in project "spring-boot", do you want to proceed? (Y/N)
y
Creating new project: spring-boot...
🚗 Provisioning remote dapr sidecars
Provisioning new dapr app id workflows... 🆕
No actor state store set. Enabling Diagrid managed workflow... ✅ ready
Creating default Diagrid Managed Pubsub... ✅
Creating default Diagrid Managed KV Store... ✅
🔧 Setting default project: spring-boot
💻 View your project in the web console: https://catalyst.diagrid.io/
🔍 Checking project readiness: spring-boot... ✅ ready
🔍 Checking App IDs readiness... ✅ ready
🚀 Launching dev session
----------------------------------------------------------------
💡 Starting applications...
⚡️ Establishing app id connectivity...
Starting app workflows... ✅
== APP - workflows == [INFO] Scanning for projects...
== APP - workflows == [INFO]
== APP - workflows == [INFO] ------------------------< io.diagrid:workflows >------------------------
== APP - workflows == [INFO] Building workflows 0.0.1-SNAPSHOT
== APP - workflows == [INFO] from pom.xml
== APP - workflows == [INFO] --------------------------------[ jar ]---------------------------------
You can check, manage and troubleshoot your workflow executions using the Diagrid Catalyst workflow visualizer. Workflows are organized by type:

But you can drill down and inspect every execution, where you can leverage the workflow visualizer:

Congratulations, you just run your first cloud workflows with Diagrid's Catalyst! 🥳
Resources & Links
Here is a list of resources with more information about Dapr & Dapr Workflows.
- Dapr PubSub on Spring Boot
- Dapr Workflows & PubSub on Spring Boot
- Dapr Workflows at Spring I/O 2025
- Dapr and Java SDK at Spring I/O 2024
- Dapr and Java SDK at Spring I/O 2023
For more complex workflow patterns check the following repository which contains examples and tests, showing the most common usages of different workflow consturcts.