A Java library for dynamic, centralized configuration management using AWS AppConfig, Secrets Manager, Parameter Store, and Hashicorp Vault. Otto Config lets you update feature toggles and application properties across distributed services without redeploying code.
- Fast Setup — Add the dependency and start using configuration immediately
- Auto Refresh — Configuration updates every 5 minutes by default, no restarts required; optional event-driven refresh available for immediate updates (see AWS Setup Guide)
- Unified API — Access properties and toggles from multiple sources through one interface
- Framework Integration — Auto-registers with Spring Boot and Helidon; works with plain Java and Clojure too
- Multiple Sources — AWS AppConfig, Secrets Manager, Parameter Store, Hashicorp Vault, and local files
- Type Safe — Built-in support for String, Boolean, and Integer types
Gradle:
dependencies {
implementation "de.otto.config:otto-config:0.1.2"
}Maven:
<dependency>
<groupId>de.otto.config</groupId>
<artifactId>otto-config</artifactId>
<version>0.1.2</version>
</dependency>Configure which configuration sources to use via application.properties or environment variables. Otto Config supports AWS AppConfig, Secrets Manager, Parameter Store, Hashicorp Vault, and local files.
# Example: Enable AWS sources for production
otto.config.sources.enabled=aws.appconfig.properties,aws.appconfig.toggles,aws.secrets,aws.ssmSee the Configuration Sources section below for detailed configuration options and the AWS Setup Guide for infrastructure setup including IAM permissions and Terraform examples.
That's it! Otto Config will automatically discover and integrate with your framework. Access your configuration through standard framework mechanisms or the ConfigurationProvider API.
For local development and testing, see the Development Guide for instructions on running with local configuration files.
Otto Config integrates automatically through Java's ServiceLoader (SPI) mechanism. Just add the dependency and it works.
Properties are available via standard Spring mechanisms:
@Value("${database.url}")
private String databaseUrl;
@Value("${feature.search.enabled}")
private boolean searchEnabled;
// For auto-refreshing properties
@PropertyValue("feature.search.enabled")
private Property<Boolean> searchEnabledProperty;Use MicroProfile Config:
@Inject
@ConfigProperty(name = "database.url")
private String databaseUrl;
@Inject
@ConfigProperty(name = "feature.search.enabled")
private Boolean searchEnabled;
// For auto-refreshing properties
@Inject
@PropertyValue("feature.search.enabled")
private Property<Boolean> searchEnabledProperty;Use the ConfigurationProvider directly:
import de.otto.config.core.Context;
import de.otto.config.provider.ConfigurationProvider;
import de.otto.config.source.CoreSourceFactory;
public class MyApplication {
private final ConfigurationProvider configurationProvider;
public MyApplication() {
Context context = Context.from("my-application");
this.configurationProvider = ConfigurationProvider.builder()
.context(context)
.source(CoreSourceFactory.createPropertiesSource(context))
.source(CoreSourceFactory.createTogglesSource(context))
.build();
}
public void processRequest() {
String databaseUrl = configurationProvider.getValue("database.url", "jdbc:h2:mem:testdb");
boolean searchEnabled = configurationProvider.getValueAsBoolean("feature.search.enabled", false);
// Use configuration...
}
}Use Java interop to access Otto Config:
Add dependency (deps.edn):
{:deps {de.otto.config/otto-config {:mvn/version "0.1.2"}}}Or with Leiningen (project.clj):
:dependencies [[de.otto.config/otto-config "0.1.2"]]Usage:
(ns myapp.config
(:import [de.otto.config.core Context]
[de.otto.config.provider ConfigurationProvider]
[de.otto.config.source CoreSourceFactory]))
(defn create-config-provider []
(let [context (Context/from "my-application")]
(-> (ConfigurationProvider/builder)
(.context context)
(.source (CoreSourceFactory/createPropertiesSource context))
(.source (CoreSourceFactory/createTogglesSource context))
(.build))))
(def config-provider (create-config-provider))
;; Get configuration values
(defn get-database-url []
(.getValue config-provider "database.url" "jdbc:h2:mem:testdb"))
(defn search-enabled? []
(.getValueAsBoolean config-provider "feature.search.enabled" false))Otto Config supports multiple configuration sources that can be used together or independently.
| Source | Properties | Toggles | Use Case |
|---|---|---|---|
| AWS AppConfig | ✅ | ✅ | Validated configs with deployment controls |
| AWS Secrets Manager | ✅ | ❌ | Encrypted secrets (passwords, API keys) |
| AWS Parameter Store | ✅ | ❌ | Hierarchical application settings |
| Hashicorp Vault | ✅ | ❌ | Enterprise secret management |
| Local Files | ✅ | ✅ | Development & testing |
Configure which sources to use in application.properties:
# For local development (default)
otto.config.sources.enabled=file
# For production with AWS
otto.config.sources.enabled=aws.appconfig.properties,aws.appconfig.toggles,aws.secrets,aws.ssm
# With Hashicorp Vault
otto.config.sources.enabled=aws.appconfig.properties,hashicorp.vaultAWS AppConfig
Automatically configured via Terraform module. see see docs/AWS_SETUP.md for more details.
AWS Secrets Manager:
Specify one or more secret ARNs in your application properties:
otto.config.aws.secrets.arn=arn:aws:secretsmanager:region:account:secret:your-secret-nameAWS Parameter Store:
Specify one or more path prefixes:
otto.config.aws.ssm.path.prefix=/your/app/configHashicorp Vault:
Configure the Vault URL, application path, and authentication credentials:
otto.config.hashicorp.vault.url=https://vault.example.com:8200
otto.config.hashicorp.vault.path=/secret/your-app
otto.config.hashicorp.vault.auth.approle.role.id=${VAULT_ROLE_ID}
otto.config.hashicorp.vault.auth.approle.secret.id=${VAULT_SECRET_ID}For detailed AWS setup instructions, IAM permissions, and Terraform examples, see docs/AWS_SETUP.md.
- AWS Setup Guide — Detailed AWS configuration for AppConfig, Secrets Manager, Parameter Store, and Vault
- Advanced Topics — Architecture diagrams, custom sources, custom providers, priority order
- Development Guide — Local development setup, VS Code configuration, testing
- Contributing — How to contribute to the project
- Publishing — Release and publishing process
Complete working examples are available in the demo/ directory:
- demo/java — Plain Java application
- demo/spring — Spring Boot application
- demo/helidon — Helidon application
Run examples locally:
# Plain Java
cd demo/java && ./gradlew run
# Spring Boot
cd demo/spring && ./gradlew bootRun --args='--spring.profiles.active=local'
# Helidon
cd demo/helidon && ./gradlew run -Pmp.config.profile=localWe welcome contributions! Please see CONTRIBUTING.md for guidelines.
Found a bug or have a feature request? Open an issue.
See docs/DEVELOPMENT.md for detailed development setup instructions.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Joseph Soliday (joseph.soliday@otto.de)
- Pavlo Fedyna (pavlo.fedyna@otto.de)
- Documentation: See the docs/ directory
- Issues: GitHub Issues
- Questions: Open a discussion or contact the maintainers