This is a Spring Boot starter that integrates OpenFeature, an open standard for feature flag
management. Add one starter dependency, set a few spring.openfeature.* properties, and feature flags work in your
application — no manual wiring of the OpenFeature SDK.
dev.openfeature.sdk.Client bean, created as soon as a FeatureProvider bean
is on the context.@ToggleOnFlag annotation gates method execution on a flag, with SpEL evaluation context
and an orElse fallback method.spring.openfeature.<provider>.* prefix.ClientCustomizer, OpenFeatureAPICustomizer, and per-provider customizers let you tweak
the auto-configured beans.userId and authorities are automatically
added to every flag evaluation context../mvnw)Every provider has its own starter. For Unleash:
Maven
<project>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.iromu.openfeature</groupId>
<artifactId>spring-boot-starter-openfeature-unleash</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.iromu.openfeature</groupId>
<artifactId>spring-boot-openfeature-dependencies</artifactId>
<version>${spring-boot-openfeature.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Gradle
dependencyManagement {
imports {
mavenBom "org.iromu.openfeature:spring-boot-openfeature-dependencies:${springBootOpenFeatureVersion}"
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.iromu.openfeature:spring-boot-starter-openfeature-unleash'
}
The BOM (spring-boot-openfeature-dependencies) pins the OpenFeature SDK and every provider library version, so you
do not need to declare versions yourself.
Configure the provider under its spring.openfeature.<provider>.* prefix in application.yml (or
application.properties). For example, Unleash:
spring:
application:
name: UnleashApplication
openfeature:
unleash:
app-name: ${spring.application.name}
environment: development
unleash-api: http://unleash-instance:4242/api/
unleash-token: 'default:development.your-api-key'
Each provider starter also accepts an enabled property (spring.openfeature.<provider>.enabled) to switch its
auto-configuration on or off. Refer to the provider’s own documentation for the full set of options.
ClientInject the auto-configured Client and evaluate flags:
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.ImmutableContext;
import dev.openfeature.sdk.Value;
@RestController
@RequestMapping("/feature")
public class FeatureController {
private final Client client;
public FeatureController(Client client) {
this.client = client;
}
@GetMapping("{name}")
public Boolean feature(@PathVariable("name") final String name) {
return this.client.getBooleanValue(name, false);
}
@GetMapping("user/{id}")
public Boolean featureOnUserId(@PathVariable("id") final String id) {
return this.client.getBooleanValue("users-flag", false,
new ImmutableContext(Map.of("userId", new Value(id))));
}
}
@ToggleOnFlagThe @ToggleOnFlag annotation (from org.iromu.openfeature.boot.aop) conditionally executes a method based on a
flag. attributes accepts a SpEL map that is evaluated into the flag evaluation context, and orElse names a
fallback method invoked when the flag evaluates to false.
Given an Unleash flag defined as:
{
"name": "users-flag",
"enabled": true,
"strategies": [
{
"name": "userWithId",
"parameters": {
"userIds": "111,234"
}
}
]
}
import org.iromu.openfeature.boot.aop.ToggleOnFlag;
@RestController
@RequestMapping("/feature")
public class UserController {
@GetMapping("annotated/user/{id}")
@ToggleOnFlag(key = "users-flag", attributes = "{'userId': #id}", orElse = "featureOnUserIdDisabled")
public String featureOnUserIdAnnotated(@PathVariable("id") final String id) {
return "User allowed";
}
public String featureOnUserIdDisabled(final String id) {
return "User not allowed";
}
}
Each backend has its own starter module under org.iromu.openfeature:
| Provider | Starter artifact |
|---|---|
| ConfigCat | spring-boot-starter-openfeature-configcat |
| Env Var | spring-boot-starter-openfeature-envvar |
| flagd | spring-boot-starter-openfeature-flagd |
| Flagsmith | spring-boot-starter-openfeature-flagsmith |
| Flipt | spring-boot-starter-openfeature-flipt |
| GoFeatureFlag | spring-boot-starter-openfeature-gofeatureflag |
| GrowthBook | spring-boot-starter-openfeature-growthbook |
| JsonLogic | spring-boot-starter-openfeature-jsonlogic |
| Multi-Provider | spring-boot-starter-openfeature-multiprovider |
| Statsig | spring-boot-starter-openfeature-statsig |
| Unleash | spring-boot-starter-openfeature-unleash |
To switch providers, replace the starter dependency and update the configuration as per the provider’s documentation.
The examples/ directory contains two runnable applications (built with the examples profile or as a separate
reactor; they resolve the starters from the local build or the snapshot repository):
unleash-simple — runs on port 9998 with a bundled in-memory fake Unleash provider; no external server
needed.unleash-advanced — runs on port 9999 against a mocked Unleash API server, using a local features.json
backup file.$ cd examples
$ mvn clean package
Then run the packaged application, for example:
$ java -jar unleash-simple/target/unleash-simple-${revision}.jar
Try the endpoints (unleash-simple):
$ curl http://localhost:9998/feature/random-boolean-flag
$ curl http://localhost:9998/feature/greet/world
And with unleash-advanced running on 9999:
$ curl http://localhost:9999/feature/annotated/user/111
All commands use the Maven wrapper from the repository root:
# Full build (compile, checkstyle, formatting, tests, coverage)
$ ./mvnw clean verify
# Skip tests
$ ./mvnw clean verify -DskipTests
# Build a single module and its dependencies
$ ./mvnw -pl spring-boot-starter-openfeature-unleash -am clean verify
Code style is enforced by Spring Java Format and Checkstyle, which run automatically during the validate phase.
Contributions are welcome! See CONTRIBUTING.md for the full guide on reporting bugs, suggesting features, code style, testing, and the pull request process.
This project is licensed under the Apache License 2.0. See the LICENSE file for details.