State Store
Since Camel 4.23
Only producer is supported
The State Store component provides a simple, unified key-value store API backed by the KeyValueRepository SPI from camel-api. It is useful for caching, session state, and scenarios where you need a simple object store (similar to MuleSoft’s Object Store).
By default, an in-memory backend is used (MemoryKeyValueRepository from camel-support), but you can plug in any KeyValueRepository implementation. The same KeyValueRepository can also be used as the backend for the Idempotent Consumer and Aggregator EIPs via the KeyValueIdempotentRepository and KeyValueAggregationRepository adapters.
When to use State Store vs individual components
Camel also provides dedicated components for Infinispan, Redis, and Caffeine. Use the dedicated component when you need the full feature set of a specific technology (e.g., Infinispan queries, Redis pub/sub, Caffeine statistics).
Use State Store when:
-
You need a simple key-value API and want to switch backends without changing route logic.
-
You are migrating from MuleSoft and want an Object Store equivalent.
-
You want backend portability — develop with in-memory, deploy with any
KeyValueRepository. -
Your use case is limited to put, get, delete, contains, keys operations.
-
You want a single backend to serve state store, idempotent consumer, and aggregation patterns.
URI Format
state-store:storeName[?options]
Where storeName is a logical name for the store. Endpoints with the same storeName share the same backend instance within the same CamelContext.
Configuring Options
Camel components are configured on two separate levels:
-
component level
-
endpoint level
Configuring Component Options
At the component level, you set general and shared configurations that are, then, inherited by the endpoints. It is the highest configuration level.
For example, a component may have security settings, credentials for authentication, urls for network connection and so forth.
Some components only have a few options, and others may have many. Because components typically have pre-configured defaults that are commonly used, then you may often only need to configure a few options on a component; or none at all.
You can configure components using:
-
the Component DSL.
-
in a configuration file (
application.properties,*.yamlfiles, etc). -
directly in the Java code.
Configuring Endpoint Options
You usually spend more time setting up endpoints because they have many options. These options help you customize what you want the endpoint to do. The options are also categorized into whether the endpoint is used as a consumer (from), as a producer (to), or both.
Configuring endpoints is most often done directly in the endpoint URI as path and query parameters. You can also use the Endpoint DSL and DataFormat DSL as a type safe way of configuring endpoints and data formats in Java.
A good practice when configuring options is to use Property Placeholders.
Property placeholders provide a few benefits:
-
They help prevent using hardcoded urls, port numbers, sensitive information, and other settings.
-
They allow externalizing the configuration from the code.
-
They help the code to become more flexible and reusable.
The following two sections list all the options, firstly for the component followed by the endpoint.
Component Options
The State Store component supports the following options which are listed below.
| Name | Description | Default | Type |
|---|---|---|---|
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean |
Endpoint Options
The State Store endpoint is configured using URI syntax:
state-store:storeName
With the following path and query parameters:
Query Parameters
| Name | Description | Default | Type |
|---|---|---|---|
The default operation to perform. Enum values:
| StateStoreOperations | ||
Time-to-live in milliseconds for entries. 0 means no expiry. | 0 | long | |
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
The backend to use. If not set, auto-discovers a single KeyValueRepository from the registry, or falls back to an in-memory store. | KeyValueRepository |
Message Headers
The State Store component supports the following message header(s), which is/are listed below:
| Name | Description | Default | Type |
|---|---|---|---|
CamelStateStoreOperation (producer) Constant: | The operation to perform. Enum values:
| StateStoreOperations | |
| Constant: | The key to use for the operation. | String | |
| Constant: | Per-message TTL override in milliseconds. Takes precedence over the endpoint ttl option. | Long |
Operations
The operation to perform is set via the URI option operation or the header CamelStateStoreOperation.
| Operation | Description | Body (input) | Result (body output) |
|---|---|---|---|
| Store a value | The value to store | The previous value (or null) |
| Store only if key absent | The value to store | The existing value (or null if stored) |
| Retrieve a value | ignored | The stored value (or null) |
| Remove a value | ignored | The removed value (or null) |
| Check if key exists | ignored | Boolean |
| List all keys | ignored | Set<String> |
| Count entries | ignored | Integer |
| Remove all entries | ignored | null |
The key is specified via the header CamelStateStoreKey (required for put, putIfAbsent, get, delete, contains).
TTL (Time-to-Live)
You can set a TTL (in milliseconds) for entries in two ways:
-
Endpoint option: applies to all
put/putIfAbsentoperations on that endpoint.state-store:myStore?operation=put&ttl=60000
-
Per-message header: the header
CamelStateStoreTtl(Long) overrides the endpoint TTL for that message.from("direct:store") .setHeader("CamelStateStoreKey", constant("myKey")) .setHeader("CamelStateStoreTtl", constant(30000L)) .to("state-store:myStore?operation=put");
A TTL of 0 (default) means no expiry.
Examples
Java DSL
-
Put and Get
-
Dynamic operation via header
-
Put if absent
from("direct:store")
.setHeader("CamelStateStoreKey", constant("myKey"))
.to("state-store:myStore?operation=put");
from("direct:retrieve")
.setHeader("CamelStateStoreKey", constant("myKey"))
.to("state-store:myStore?operation=get"); from("direct:dynamic")
.setHeader("CamelStateStoreOperation", constant("put"))
.setHeader("CamelStateStoreKey", constant("myKey"))
.to("state-store:myStore"); from("direct:init")
.setHeader("CamelStateStoreKey", constant("counter"))
.to("state-store:myStore?operation=putIfAbsent"); Backends
Backend auto-discovery
If no backend option is specified on the endpoint, the component automatically looks up a KeyValueRepository bean from the Camel registry. If exactly one is found, it is used for all endpoints. If none is found, the default in-memory backend (MemoryKeyValueRepository) is used.
This means you can configure a backend once (via Java or properties) and all state-store endpoints will use it without needing backend=#beanName on each endpoint URI.
Custom Backend
Implement the KeyValueRepository interface (from org.apache.camel.spi) to create your own backend:
public class MyCustomBackend extends ServiceSupport implements KeyValueRepository {
@Override
public Object get(String key) {
// retrieve the value
}
@Override
public Object put(String key, Object value, long ttlMillis) {
// store the value; return the previous value or null
}
@Override
public Object delete(String key) {
// remove and return the value
}
@Override
public boolean contains(String key) {
// check existence
}
@Override
public Set<String> keys() {
// return all keys
}
@Override
public void clear() {
// remove all entries
}
} The putIfAbsent and size methods have default implementations but can be overridden for better performance with backends that support these operations natively.
Then reference it via bean or let auto-discovery find it:
from("direct:store")
.to("state-store:myStore?operation=put&backend=#myCustomBackend"); Sharing a backend across patterns
Because KeyValueRepository is the unified SPI, the same implementation can be reused as the backend for the Idempotent Consumer and Aggregator EIPs:
@BindToRegistry("kvRepo")
public KeyValueRepository kvRepo() {
return new MemoryKeyValueRepository();
} With a single KeyValueRepository in the registry:
-
The State Store component auto-discovers and uses it.
-
The Idempotent Consumer EIP auto-discovers and wraps it in a
KeyValueIdempotentRepository. -
The Aggregator EIP auto-discovers and wraps it in a
KeyValueAggregationRepository.
No explicit wiring is needed — all three patterns share the same backend.