Skip to main content

How to develop a Workflow in Java

In the Temporal Java SDK programming model, a Workflow definition comprises a Workflow interface annotated with @WorkflowInterface and a Workflow implementation that implements the Workflow interface.

The Workflow interface is a Java interface and is annotated with @WorkflowInterface. Each Workflow interface must have only one method annotated with @WorkflowMethod. The method name can be used to denote the Workflow Type.

// Workflow interface
public interface YourWorkflow {

String yourWFMethod(Arguments args);

However, when using dynamic Workflows, do not specify a @WorkflowMethod, and implement the DynamicWorkflow directly in the Workflow implementation code.

The @WorkflowMethod identifies the method that is the starting point of the Workflow Execution. The Workflow Execution completes when this method completes.

You can create interface inheritance hierarchies to reuse components across other Workflow interfaces. The interface inheritance approach does not apply to @WorkflowMethod annotations.

A Workflow implementation implements a Workflow interface.

// Define the Workflow implementation which implements our getGreeting Workflow method.
public static class GreetingWorkflowImpl implements GreetingWorkflow {

To call Activities in your Workflow, call the Activity implementation.

Use ExternalWorkflowStub to start or send Signals from within a Workflow to other running Workflow Executions.

You can also invoke other Workflows as Child Workflows with Workflow.newChildWorkflowStub() or Workflow.newUntypedChildWorkflowStub() within a Workflow Definition.

Use DynamicWorkflow to implement Workflow Types dynamically. Register a Workflow implementation type that extends DynamicWorkflow to implement any Workflow Type that is not explicitly registered with the Worker.

The dynamic Workflow interface is implemented with the execute method. This method takes in EncodedValues that are inputs to the Workflow Execution. These inputs can be specified by the Client when invoking the Workflow Execution.

public class MyDynamicWorkflow implements DynamicWorkflow {
public Object execute(EncodedValues args) {

Customize Workflow Type

The Workflow Type defaults to the short name of the Workflow interface. In the following example, the Workflow Type defaults to NotifyUserAccounts.


public interface NotifyUserAccounts {
void notify(String[] accountIds);

To overwrite this default naming and assign a custom Workflow Type, use the @WorkflowMethod annotation with the name parameter. In the following example, the Workflow Type is set to Abc.


public interface NotifyUserAccounts {
@WorkflowMethod(name = "Abc")
void notify(String[] accountIds);

When you set the Workflow Type this way, the value of the name parameter does not have to start with an uppercase letter.


A method annotated with @WorkflowMethod can have any number of parameters.

We recommend passing a single parameter that contains all the input fields to allow for adding fields in a backward-compatible manner.

Note that all inputs should be serializable by the default Jackson JSON Payload Converter.

You can create a custom object and pass it to the Workflow method, as shown in the following example.

public interface YourWorkflow {
String yourWFMethod(CustomObj customobj);
// ...

Return values

Workflow method arguments and return values must be serializable and deserializable using the provided DataConverter.

The execute method for DynamicWorkflow can return type Object. Ensure that your Client can handle an Object type return or is able to convert the Object type response.

Related references:

Logic requirements

When defining Workflows using the Temporal Java SDK, the Workflow code must be written to execute effectively once and to completion.

The following constraints apply when writing Workflow Definitions:

  • Do not use mutable global variables in your Workflow implementations. This will ensure that multiple Workflow instances are fully isolated.
  • Your Workflow code must be deterministic. Do not call non-deterministic functions (such as non-seeded random or UUID.randomUUID()) directly from the Workflow code. The Temporal SDK provides specific API for calling non-deterministic code in your Workflows.
  • Do not use programming language constructs that rely on system time. For example, only use Workflow.currentTimeMillis() to get the current time inside a Workflow.
  • Do not use native Java Thread or any other multi-threaded classes like ThreadPoolExecutor. Use Async.function or Async.procedure, provided by the Temporal SDK, to execute code asynchronously.
  • Do not use synchronization, locks, or other standard Java blocking concurrency-related classes besides those provided by the Workflow class. There is no need for explicit synchronization because multi-threaded code inside a Workflow is executed one thread at a time and under a global lock.
    • Call Workflow.sleep instead of Thread.sleep.
    • Use Promise and CompletablePromise instead of Future and CompletableFuture.
    • Use WorkflowQueue instead of BlockingQueue.
  • Use Workflow.getVersion when making any changes to the Workflow code. Without this, any deployment of updated Workflow code might break already running Workflows.
  • Do not access configuration APIs directly from a Workflow because changes in the configuration might affect a Workflow Execution path. Pass it as an argument to a Workflow function or use an Activity to load it.
  • Use DynamicWorkflow when you need a default Workflow that can handle all Workflow Types that are not registered with a Worker. A single implementation can implement a Workflow Type which by definition is dynamically loaded from some external source. All standard WorkflowOptions and determinism rules apply to Dynamic Workflow implementations.

Java Workflow reference: