Java client
The Camunda Java Client is the official Java library for building process applications that integrate with Camunda 8. Whether you are orchestrating microservices, managing human tasks, or visualizing process data, this client provides everything needed to interact with the Orchestration Cluster programmatically.
The Camunda Java Client is part of the Camunda 8 public API and follows Semantic Versioning (except for alpha features). Minor and patch releases will not introduce breaking changes.
What is the Camunda Java Client?
The Camunda Java Client is a comprehensive library enabling Java developers to:
- Deploy processes and decisions to Camunda 8 clusters
- Start and manage processes programmatically
- Implement job workers to handle automated tasks within your processes
- Query and manage process data via the Orchestration Cluster API
It supports both REST and gRPC protocols, authentication setup, and provides robust error handling with retry mechanisms.
The Camunda Java Client replaces the Zeebe Java Client as of version 8.8.
- Provides improved structure and full Orchestration Cluster API support
- The Zeebe Java Client will be removed in version 8.10
- Migrate before upgrading to 8.10 to avoid breaking changes
See our migration guide for details.
What can you build with it?
Use the Camunda Java Client to build:
- Job workers that perform automated tasks and call external systems (APIs, databases, file systems)
- Integration services that connect Camunda processes with existing systems or third-party services
- Data processing applications that leverage process data for visualization, analytics, or business intelligence
Getting started in three steps
Step 1: Add the dependency
Add the Camunda Java Client to your project:
Maven:
<dependency>
<groupId>io.camunda</groupId>
<artifactId>camunda-client-java</artifactId>
<version>${camunda.version}</version>
</dependency>
Gradle:
implementation 'io.camunda:camunda-client-java:${camunda.version}'
Use the latest version from Maven Central.
Step 2: Connect to your Camunda 8 cluster
Instantiate a client to connect to your Camunda 8 cluster. Choose the authentication method based on your environment:
- No Authentication
- Basic Authentication
- OIDC Access Token Authentication - Self-Managed
- OIDC Access Token Authentication - SaaS
- OIDC Access Token Authentication with X.509 Client Certificate
Use for: Local development when security is not required.
private static final String CAMUNDA_GRPC_ADDRESS = "[Address of Zeebe API (gRPC) - default: http://localhost:26500]";
private static final String CAMUNDA_REST_ADDRESS = "[Address of the Orchestration Cluster API - default: http://localhost:8080]";
public static void main(String[] args) {
try (CamundaClient client = CamundaClient.newClientBuilder()
.grpcAddress(URI.create(CAMUNDA_GRPC_ADDRESS))
.restAddress(URI.create(CAMUNDA_REST_ADDRESS))
.usePlaintext()
.build()) {
// Test the connection
client.newTopologyRequest().send().join();
System.out.println("Connected to Camunda 8!");
}
}
What this code does
- Creates a no-authentication provider – Configures the client to skip authentication.
- Builds an unencrypted client – Uses plaintext communication for local development.
- Connects to both APIs – Configures access to the Zeebe gRPC and Orchestration Cluster REST APIs.
- Tests the connection – Verifies connectivity by requesting cluster topology information.
Environment variables option
You can also set connection details via environment variables to create the client more simply:
export CAMUNDA_GRPC_ADDRESS='[Address of Zeebe API (gRPC) - default: http://localhost:26500]'
export CAMUNDA_REST_ADDRESS='[Address of the Orchestration Cluster API - default: http://localhost:8080]'
CamundaClient client = CamundaClient.newClientBuilder().usePlaintext().build();
The client will automatically read the environment variables and configure the appropriate authentication method.
Ensure addresses are in absolute URI format: scheme://host(:port)
.
Use for: Development or testing environments with username/password protection.
private static final String CAMUNDA_GRPC_ADDRESS = "[Address of Zeebe API (gRPC) - default: http://localhost:26500]";
private static final String CAMUNDA_REST_ADDRESS = "[Address of the Orchestration Cluster API - default: http://localhost:8080]";
private static final String CAMUNDA_BASIC_AUTH_USERNAME = "[Your username - default: demo]";
private static final String CAMUNDA_BASIC_AUTH_PASSWORD = "[Your password - default: demo]";
public static void main(String[] args) {
CredentialsProvider credentialsProvider = new BasicAuthCredentialsProviderBuilder()
.username(CAMUNDA_BASIC_AUTH_USERNAME)
.password(CAMUNDA_BASIC_AUTH_PASSWORD)
.build();
try (CamundaClient client = CamundaClient.newClientBuilder()
.grpcAddress(URI.create(CAMUNDA_GRPC_ADDRESS))
.restAddress(URI.create(CAMUNDA_REST_ADDRESS))
// uncomment to use an unencrypted transport (plain http)
// we advise to use encrypted connections to not leak credentials
// .usePlaintext()
.credentialsProvider(credentialsProvider)
.build()) {
// Test the connection
client.newTopologyRequest().send().join();
System.out.println("Connected to Camunda 8!");
}
}
What this code does
- Sets up username/password authentication – Configures the client to use basic credentials.
- Builds a secure client – Establishes an encrypted connection to the cluster (default).
- Connects to both APIs – Configures access to the Zeebe gRPC and Orchestration Cluster REST APIs.
- Tests the connection – Verifies authentication by requesting cluster topology information.
Environment variables option
You can also set connection details via environment variables to create the client more simply:
export CAMUNDA_GRPC_ADDRESS='[Address of Zeebe API (gRPC) - default: http://localhost:26500]'
export CAMUNDA_REST_ADDRESS='[Address of the Orchestration Cluster API - default: http://localhost:8080]'
export CAMUNDA_BASIC_AUTH_USERNAME='[Your username - default: demo]'
export CAMUNDA_BASIC_AUTH_PASSWORD='[Your password - default: demo]'
CamundaClient client = CamundaClient.newClientBuilder().build();
The client will automatically read the environment variables and configure the appropriate authentication method.
- Ensure addresses use absolute URI format:
scheme://host(:port)
. - By default, environment variables override any values provided in Java code. To give Java code values precedence, use the
.applyEnvironmentOverrides(false)
method onBasicAuthCredentialsProviderBuilder
. - The client adds an
Authorization
header to each request with the valueBasic username:password
(whereusername:password
is base64 encoded).
Use for: Self-Managed production environments with OIDC access token authentication.
private static final String CAMUNDA_GRPC_ADDRESS = "[Address of Zeebe API (gRPC) - default: http://localhost:26500]";
private static final String CAMUNDA_REST_ADDRESS = "[Address of the Orchestration Cluster API - default: http://localhost:8080]";
private static final String CAMUNDA_AUTHORIZATION_SERVER_URL = "[OAuth URL e.g. http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token]";
private static final String AUDIENCE = "[Audience]";
private static final String CLIENT_ID = "[Client ID]";
private static final String CLIENT_SECRET = "[Client Secret]";
public static void main(String[] args) {
CredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder()
.authorizationServerUrl(CAMUNDA_AUTHORIZATION_SERVER_URL)
.audience(AUDIENCE)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.build();
try (CamundaClient client = CamundaClient.newClientBuilder()
.grpcAddress(URI.create(CAMUNDA_GRPC_ADDRESS))
.restAddress(URI.create(CAMUNDA_REST_ADDRESS))
.credentialsProvider(credentialsProvider)
.build()) {
// Test the connection
client.newTopologyRequest().send().join();
System.out.println("Connected to Camunda 8!");
}
}
What this code does
- Sets up OAuth2 authentication – Configures the client to use OAuth tokens from your identity provider.
- Builds a secure client – Establishes an encrypted connection to your self-managed cluster (default).
- Connects to both APIs – Configures access to the Zeebe gRPC and Orchestration Cluster REST APIs.
- Tests the connection – Verifies OAuth authentication by requesting cluster topology information.
Environment variables option
You can also set connection details via environment variables to create the client more simply:
export CAMUNDA_GRPC_ADDRESS='[Address of Zeebe API (gRPC) - default: http://localhost:26500]'
export CAMUNDA_REST_ADDRESS='[Address of the Orchestration Cluster API - default: http://localhost:8080]'
export CAMUNDA_AUTHORIZATION_SERVER_URL='[OAuth URL e.g. http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token]'
export CAMUNDA_TOKEN_AUDIENCE='[Audience]'
export CAMUNDA_CLIENT_ID='[Client ID]'
export CAMUNDA_CLIENT_SECRET='[Client Secret]'
CamundaClient client = CamundaClient.newClientBuilder().build();
The client will automatically read the environment variables and configure the appropriate authentication method.
- Ensure addresses use absolute URI format:
scheme://host(:port)
. - By default, environment variables override any values provided in Java code. To give Java code values precedence, use the
.applyEnvironmentOverrides(false)
method onOAuthCredentialsProviderBuilder
. - The client adds an
Authorization
header to each request with the valueBearer <token>
. The token is obtained from the authorization server, cached to avoid unnecessary requests, and refreshed lazily upon expiration.
Use for: Camunda 8 SaaS environments. Get the values below from your Camunda Console client credentials.
private static final String CAMUNDA_CLUSTER_ID = "[Cluster ID from Console]";
private static final String CAMUNDA_CLIENT_ID = "[Client ID from Console]";
private static final String CAMUNDA_CLIENT_SECRET = "[Client Secret from Console]";
private static final String CAMUNDA_CLUSTER_REGION = "[Cluster Region from Console]";
public static void main(String[] args) {
try (CamundaClient client = CamundaClient.newCloudClientBuilder()
.withClusterId(CAMUNDA_CLUSTER_ID)
.withClientId(CAMUNDA_CLIENT_ID)
.withClientSecret(CAMUNDA_CLIENT_SECRET)
.withRegion(CAMUNDA_CLUSTER_REGION)
.build()) {
// Test the connection
client.newTopologyRequest().send().join();
System.out.println("Connected to Camunda 8!");
}
}
What this code does
- Sets up SaaS authentication – Configures the client to connect to Camunda 8 SaaS using your cluster credentials.
- Builds a cloud client – Creates a client optimized for SaaS with automatic endpoint discovery.
- Connects to your cluster – Uses your cluster ID and region to locate and connect to the correct SaaS instance.
- Tests the connection – Verifies SaaS authentication by requesting cluster topology information.
Environment variables option
You can also set connection details via environment variables to create the client more simply:
export ZEEBE_GRPC_ADDRESS='[Zeebe gRPC Address from Console]'
export ZEEBE_REST_ADDRESS='[Zeebe REST Address from Console]'
export CAMUNDA_OAUTH_URL='[OAuth URL from Console]'
export CAMUNDA_TOKEN_AUDIENCE='[Audience from Console - default: zeebe.camunda.io]'
export CAMUNDA_CLIENT_ID='[Client ID from Console]'
export CAMUNDA_CLIENT_SECRET='[Client Secret from Console]'
CamundaClient client = CamundaClient.newClientBuilder().build();
The client will automatically read the environment variables and configure the appropriate authentication method.
Ensure addresses are in absolute URI format: scheme://host(:port)
.
Use for: Production environments with X.509 certificate-based authentication.
Several identity providers, such as Keycloak, support client X.509 authentication as an alternative to the client credentials flow.
Prerequisites
- Properly configured KeyStore and TrustStore
- Both the Spring Camunda application and identity provider share the same CA trust certificates
- Certificates for both Spring Camunda and the identity provider are signed by a trusted CA
- The Spring Camunda application certificate has a proper Distinguished Name (DN), e.g.,
CN=My Camunda Client, OU=Camunda Users, O=Best Company, C=DE
- The application DN is registered in the identity provider client authorization details
private static final String CAMUNDA_GRPC_ADDRESS = "[Address of Zeebe API (gRPC) - default: http://localhost:26500]";
private static final String CAMUNDA_REST_ADDRESS = "[Address of the Orchestration Cluster API - default: http://localhost:8080]";
private static final String OAUTH_URL = "[OAuth URL e.g. http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token]";
private static final String AUDIENCE = "[Audience - default: zeebe-api]";
private static final String CLIENT_ID = "[Client ID]";
private static final String CLIENT_SECRET = "[Client Secret]";
private static final Path KEYSTORE_PATH = Paths.get("/path/to/keystore.p12");
private static final String KEYSTORE_PASSWORD = "password";
private static final String KEYSTORE_KEY_PASSWORD = "password";
private static final Path TRUSTSTORE_PATH = Paths.get("/path/to/truststore.jks");
private static final String TRUSTSTORE_PASSWORD = "password";
public static void main(String[] args) {
CredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder()
.authorizationServerUrl(OAUTH_URL)
.audience(AUDIENCE)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.keystorePath(KEYSTORE_PATH)
.keystorePassword(KEYSTORE_PASSWORD)
.keystoreKeyPassword(KEYSTORE_KEY_PASSWORD)
.truststorePath(TRUSTSTORE_PATH)
.truststorePassword(TRUSTSTORE_PASSWORD)
.build();
try (CamundaClient client = CamundaClient.newClientBuilder()
.grpcAddress(URI.create(CAMUNDA_GRPC_ADDRESS))
.restAddress(URI.create(CAMUNDA_REST_ADDRESS))
.credentialsProvider(credentialsProvider)
.build()) {
// Test the connection
client.newTopologyRequest().send().join();
System.out.println("Connected to Camunda 8!");
}
}
What this code does
- Sets up X.509 certificate authentication – Configures the client to authenticate using client certificates with OAuth.
- Builds a secure client – Establishes an encrypted connection using mutual TLS authentication.
- Connects to both APIs – Configures access to the Zeebe gRPC and Orchestration Cluster REST APIs.
- Tests the connection – Verifies certificate authentication by requesting cluster topology information.
Environment variables option
You can also set connection details via environment variables to create the client more simply:
export CAMUNDA_GRPC_ADDRESS='[Address of Zeebe API (gRPC) - default: http://localhost:26500]'
export CAMUNDA_REST_ADDRESS='[Address of the Orchestration Cluster API - default: http://localhost:8080]'
export CAMUNDA_OAUTH_URL='[OAuth URL e.g. http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token]'
export CAMUNDA_TOKEN_AUDIENCE='[Audience - default: zeebe-api]'
export CAMUNDA_CLIENT_ID='[Client ID]'
export CAMUNDA_CLIENT_SECRET='[Client Secret]'
export CAMUNDA_SSL_CLIENT_KEYSTORE_PATH='[Keystore path]'
export CAMUNDA_SSL_CLIENT_KEYSTORE_SECRET='[Keystore password]'
export CAMUNDA_SSL_CLIENT_KEYSTORE_KEY_SECRET='[Keystore material password]'
export CAMUNDA_SSL_CLIENT_TRUSTSTORE_PATH='[Truststore path]'
export CAMUNDA_SSL_CLIENT_TRUSTSTORE_SECRET='[Truststore password]'
CamundaClient client = CamundaClient.newClientBuilder().build();
The client automatically reads environment variables and configures the appropriate authentication method.
Refer to your identity provider documentation for configuring X.509 authentication. For example, see Keycloak.
- Ensure addresses use absolute URI format:
scheme://host(:port)
. - By default, environment variables override any values provided in Java code. To give Java code values precedence, use the
.applyEnvironmentOverrides(false)
method onOAuthCredentialsProviderBuilder
.
Step 3: Start building your process application
With a connected client, you are ready to build your process application. Below are the core operations you’ll typically perform, along with guidance on the next steps.
Essential operations
Deploy a process:
final DeploymentEvent deploymentEvent = client.newDeployResourceCommand()
.addResourceFromClasspath("process.bpmn")
.send()
.join();
This deploys your BPMN process definition to the cluster. Place your .bpmn
files in src/main/resources
and reference them by filename.
Start a process instance:
final ProcessInstanceEvent processInstanceEvent = client.newCreateInstanceCommand()
.bpmnProcessId("my-process")
.latestVersion()
.variables(Map.of("orderId", "12345", "amount", 100.0))
.send()
.join();
This creates a new instance of your process. The bpmnProcessId
should match the Process ID from your BPMN file, and you can pass initial variables as a Map.
For a comprehensive example demonstrating these steps, see the DeployAndComplete example in the Camunda 8 examples repository. This example illustrates a complete workflow from process deployment to job completion.
Key features and capabilities
- Full Orchestration Cluster 8 API support: Access all Orchestration Cluster API capabilities, including process deployment, management, job handling, and querying process data.
- Multiple authentication methods: Supports no authentication (development), basic authentication, and OIDC access tokens for production environments.
- Automatic token management: Handles authentication token acquisition and renewal automatically—no manual token management required.
- Protocol flexibility: Choose between REST and gRPC protocols depending on your requirements and infrastructure.
Next steps and resources
Learn the fundamentals
- Job worker implementation – Build workers to handle automated tasks
- Process testing – Test your processes with Camunda Process Test
- Getting Started Tutorial – Complete walkthrough with Modeler, Operate, and Spring SDK
Advanced topics
- Logging configuration – Set up proper logging for your application
- Client documentation – Complete Javadoc reference
Need help?
- Camunda Community Forum – Get help from the community
- GitHub repository – Report issues and contribute