
Build a Temporal Application from scratch in Java
- Build the application
- Test and run a Worker
- Run the application
Creating reliable applications is a difficult task. Temporal lets you create fault-tolerant, resilient applications using programming languages you already know, so you can build complex applications that execute successfully and recover from failures. In this tutorial, you'll build your first Temporal Application from scratch using the Temporal Java SDK.
The Temporal Application will consist of the following pieces:
- A Workflow: a Workflow defines a sequence of steps. With Temporal, those steps are defined by writing code, known as a Workflow Definition, and are carried out by running that code, which results in a Workflow Execution.
- An Activity: Activities are methods called during Workflow Execution and represent the execution aspect of your business logic. The Workflow you'll create executes a single Activity, which takes a string from the Workflow as input and returns a formatted version of this string to the Workflow.
- A Worker: Workers host the Activity and Workflow code and are responsible for processing Workflow and Activity Tasks.
- A client: code that triggers the execution of the Workflow on the Temporal Server.
You'll also write a unit test to ensure your Workflow executes successfully.
Prerequisites
Before starting this tutorial:
- Set up a local development environment for developing Temporal applications using the Java programming language.
- Follow the tutorial Run your first Temporal application with the Java SDK to gain a better understanding of what Temporal is and how its components fit together.
- Ensure the build tool Maven is installed and ready to use to create a Java project.
Create a new Java project
To get started with the Temporal Java SDK, you'll create a new Java application, just like any other Java program you're creating. Then you'll add the Temporal SDK package to your project.
In a terminal, create a new project directory called hello-world-temporal:
mkdir hello-world-temporal
Switch to the new directory:
cd hello-world-temporal
Create a new Java project with Maven by running the following command:
mvn -B archetype:generate \
-DgroupId=helloworldapp \
-DartifactId=app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4
This command creates a directory name app that contains your Java application named helloworldapp.
Your output will be similar to this:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> archetype:3.2.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< archetype:3.2.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- archetype:3.2.1:generate (default-cli) @ standalone-pom ---
[WARNING] Parameter 'localRepository' is deprecated core expression; Avoid use of ArtifactRepository type. If you need access to local repository, switch to '${repositorySystemSession}' expression and get LRM from it instead.
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: helloworldapp
[INFO] Parameter: artifactId, Value: app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: helloworldapp
[INFO] Parameter: packageInPathFormat, Value: helloworldapp
[INFO] Parameter: package, Value: helloworldapp
[INFO] Parameter: groupId, Value: helloworldapp
[INFO] Parameter: artifactId, Value: app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Project created from Archetype in dir: /Users/max/Code/Temporal/hello-world-project-template-java/tmp/app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.037 s
[INFO] Finished at: 2025-11-05T10:05:47-05:00
[INFO] ------------------------------------------------------------------------
Next you will need to ensure that the Java version Maven is compiling against supports building Temporal Applications. Temporal requires a minimum version of Java 1.8. Open the Maven configuration file at app/pom.xml and locate the <properties> tag that contains the <maven.compiler.source> and <maven.compiler.target> tags. Update these two property tags with 1.8.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
Next you will add the Temporal SDK as a dependency, along with a handful of other libraries for testing and logging. In pom.xml replace the generated <dependencies> section in the file with the following:
<dependencies>
<dependency>
<groupId>io.temporal</groupId>
<artifactId>temporal-sdk</artifactId>
<version>1.31.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>io.temporal</groupId>
<artifactId>temporal-testing</artifactId>
<version>1.31.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.20.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Below is a more detailed explanation about the dependencies you will be installing:
temporal-sdk- The Temporal SDK for use in your application.
slf4j-nop- A NOOP logging package to suppress logging warnings. This is not intended for production use and a proper logger should be implemented.
temporal-testing- The necessary packages for testing a Temporal application.
junit- The core Java Unit Testing framework.
mockito-core- A mocking framework in Java to be used during testing.
Once you have added the build dependencies, perform a test build on your application.
Change directory into the app directory:
cd app
From the app directory of your project that contains the pom.xml execute the following command:
mvn compile
You will see output similar to this if your build was successful. If it is your first time running mvn compile you may see more output of the dependencies being downloaded:
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< helloworldapp:app >--------------------------
[INFO] Building app 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/3.0.2/maven-resources-plugin-3.0.2.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/3.0.2/maven-resources-plugin-3.0.2.pom (7.1 kB at 42 kB/s)
...
Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-compiler-javac/2.8.4/plexus-compiler-javac-2.8.4.jar (21 kB at 453 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/com/thoughtworks/qdox/qdox/2.0-M9/qdox-2.0-M9.jar (317 kB at 6.3 MB/s)
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/max/Code/Temporal/tmp/app/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.973 s
[INFO] Finished at: 2025-11-05T10:47:31-05:00
[INFO] ------------------------------------------------------------------------
Finally, your build tool may have created a default App.java file. You won't need this file for this tutorial, so delete it.
rm -f app/src/main/java/helloworldapp/App.java
With your project workspace configured, you're ready to create your first Temporal Activity and Workflow. You'll start with the Workflow.
Create a Workflow
Workflows are where you configure and organize the execution of Activities. You write a Workflow using one of the programming languages supported by a Temporal SDK. This code is known as a Workflow Definition.
In the Temporal Java SDK, a Workflow Definition is made of two parts:
- A Workflow Interface, which is an interface annotated with
@WorkflowInterface. This interface contains a single method signature annotated with@WorkflowMethod. - A class that implements the interface, providing the code that runs when the Workflow is executed.
Create HelloWorldWorkflow.java in the source code location of your project at app/src/main/java/helloworldapp/ and add the following code to create a HelloWorldWorkflow interface that defines the expected functionality of your workflow:
package helloworldapp;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface HelloWorldWorkflow {
/**
* This is the method that is executed when the Workflow Execution is started. The Workflow
* Execution completes when this method finishes execution.
*/
@WorkflowMethod
String getGreeting(String name);
}
The HelloWorldWorkflow interface is annotated with @WorkflowInterface, signifying that the interface is a Temporal Workflow. Within this interface is a single method getGreeting(String name) that takes a single String parameter, name, and is annotated with @WorkflowMethod. This annotation denotes the starting point of Workflow execution and execution completes when this method returns.
Next, create HelloWorldWorkflowImpl.java and add the following code to implement the Workflow and define its methods:
package helloworldapp;
import io.temporal.activity.ActivityOptions;
import io.temporal.workflow.Workflow;
import java.time.Duration;
public class HelloWorldWorkflowImpl implements HelloWorldWorkflow {
/*
* At least one of the following options needs to be defined:
* - setStartToCloseTimeout
* - setScheduleToCloseTimeout
*/
ActivityOptions options = ActivityOptions.newBuilder()
.setStartToCloseTimeout(Duration.ofSeconds(60))
.build();
/*
* Define the HelloWorldActivity stub. Activity stubs are proxies for activity invocations that
* are executed outside of the workflow thread on the activity worker, that can be on a
* different host. Temporal is going to dispatch the activity results back to the workflow and
* unblock the stub as soon as activity is completed on the activity worker.
*
* The activity options that were defined above are passed in as a parameter.
*/
private final HelloWorldActivities activity = Workflow.newActivityStub(HelloWorldActivities.class, options);
// This is the entry point to the Workflow.
@Override
public String getGreeting(String name) {
/**
* If there were other Activity methods they would be orchestrated here or from within other Activities.
* This is a blocking call that returns only after the activity has completed.
*/
return activity.composeGreeting(name);
}
}
In this implementation, you have specified that the Start-to-Close Timeout for your Activity will be one minute, meaning that your Activity has one minute to begin before it times out. Of all the Temporal timeout options, startToCloseTimeOut is the one you should always set. In this implementation you create a HelloWorldActivities stub that will act as a proxy for activity invocations.
Notice that Workflow.newActivityStub() uses an interface of HelloWorldActivities to create the activity stub, not the Activity implementation. The workflow communicates with an Activity through its public interface and is not aware of its implementation.
Finally HelloWorldWorkflowImpl implements the getGreeting Workflow Method from the Workflow Interface. The method returns the result of the Activity.
With your Workflow Definition created, you're ready to create the composeGreeting Activity.
Create an Activity
In a Temporal Application, Activities are where you execute any operation that is prone to failure or access external services or systems, such as API requests or database calls. Your Workflow Definitions call Activities and process the results. Complex Temporal Applications have Workflows that invoke many Activities, using the results of one Activity to execute another.
For this tutorial, your Activity won't be complex; you'll create an Activity that takes a string as input and uses it to create a new string as output, which is then returned to the Workflow. This will let you see how Workflows and Activities work together without building something complicated.
With the Temporal Java SDK, you define Activities similarly to how you define Workflows: using an interface and an implementation.
Create the file HelloWorldActivities.java in app/src/main/java/helloworldapp/ and add the following code to define the HelloWorldActivities interface:
package helloworldapp;
import io.temporal.activity.ActivityInterface;
@ActivityInterface
public interface HelloWorldActivities {
// Define your activity methods which can be called during workflow execution
String composeGreeting(String name);
}
The HelloWorldActivities interface is annotated with @ActivityInterface, signifying that the interface is a Temporal Activity. Within this interface is a single method signature, composeGreeting(String name). Activity Interfaces can have multiple methods, but for this example you'll have just the one.
Next, create HelloWorldActivitiesImpl.java in app/src/main/java/helloworldapp/ and add the following code to implement the Activity and define its methods:
package helloworldapp;
public class HelloWorldActivitiesImpl implements HelloWorldActivities {
@Override
public String composeGreeting(String name) {
return "Hello " + name + "!";
}
}
This class implements the single method from the interface named composeGreeting to compose a String that returns a standard "Hello World!" message using the passed in parameter.
Your Activity Definition can accept input parameters just like Workflow Definitions. Review the Activity parameters section of the Temporal documentation for more details, as there are some limitations you'll want to be aware of when running more complex applications.
You've completed the logic for the application; you have a Workflow and an Activity defined. Before moving on to configuring your Worker, you'll write a unit test for your Workflow.
Get notified when we launch new educational content
New courses, tutorials, and learning resources - straight to your inbox.