how-to

Feature Flags in Java and Spring, Done Right - A 2026 Tutorial

How to implement feature flags in Java and Spring Boot, from a config property to four production SDKs. Real code, Spring integration, and how to choose a platform.

Published:

Most Java teams start feature flags the same way: an if on a boolean bound from application.yml. That is fine until the flag needs to change without a redeploy, or roll out to 10 percent of users, or be flipped by someone who does not have deploy access. This guide covers the whole range - Spring’s built-in toggles first, then four production SDKs with real code and honest trade-offs.

The principle is the same in every language: decouple deploy from release. Ship the code dark, then turn it on when you are ready, gradually, and kill it instantly if a metric goes bad. Spring gives you clean hooks for the simple end, and the SDKs handle the dynamic end where the value is.

Step 1: Spring’s built-in toggles (no dependency)

For flags that change rarely and only at deploy time, Spring already has what you need. Bind a property:

# application.yml
features:
  new-checkout: true
  fast-search: false
@ConfigurationProperties(prefix = "features")
public class FeatureFlags {
    private boolean newCheckout;
    private boolean fastSearch;
    // getters and setters
}

Then gate behavior, or gate an entire bean:

@Service
@ConditionalOnProperty(name = "features.new-checkout", havingValue = "true")
public class NewCheckoutService implements CheckoutService { }

What you get: zero dependencies, native Spring, no vendor. What you lose: a change needs a restart (or a Spring Cloud Config /refresh), and there is no per-user targeting, percentage rollout, or audit log. Cross the moment you need runtime control, and a platform pays for itself. Our feature flag management guide marks that line.

Step 2: Pick a platform, and know why

Four options ship real Java SDKs and slot into Spring the same way. They differ on pricing model and self-host, not on Java support.

ToolJava SDKModelSelf-hostBest for
LaunchDarklyYes$10/connection + $8.33/1k MAUNoDeepest tooling
UnleashYes$0 self-hosted (AGPL-3.0)YesOwn-infra JVM teams
FlagsmithYes$0 / $40/mo annualYes (BSD-3)Cheap open source
ConfigCatYesFlat, no per-MAUNoPredictable pricing

Step 3: The Spring integration pattern

Every one of these follows the same shape in Spring: create the SDK client once as a singleton @Bean, inject it, evaluate per request. Illustrative pattern:

@Configuration
public class FeatureFlagConfig {
    @Bean(destroyMethod = "close")
    public FeatureClient featureClient() {
        return new FeatureClient("your-sdk-key");
    }
}

@Service
public class CheckoutService {
    private final FeatureClient flags;

    public CheckoutService(FeatureClient flags) {
        this.flags = flags;
    }

    public void checkout(User user) {
        if (flags.boolVariation("new-checkout", user.getId(), false)) {
            newCheckout();
        } else {
            legacyCheckout();
        }
    }
}

Two rules carry the most weight. Make the client a singleton bean - Spring’s default scope handles this - so you initialize once and the background refresh thread runs once. And always pass a default (the false above) so a flag-service outage degrades to the safe path instead of throwing. destroyMethod = "close" lets Spring shut the client down cleanly on app stop.

Step 4: Choose by the reason, not the ranking

If you want the deepest tooling and can forecast cost: LaunchDarkly. It has a Java SDK, around 38 SDKs total, and guarded releases that auto-roll-back on a bad metric - genuinely best-in-class. The gotcha is the bill. It charges $10 per service connection per month plus $8.33 per 1,000 client-side MAU on your highest-volume context kind, and Vendr’s contract data puts the median around $72,000 a year, ranging $19,500 to $165,700. Model your context volume before you commit; how to reduce LaunchDarkly costs helps if it runs high.

If you run your own infra: Unleash. AGPL-3.0, a Java SDK, and self-hostable including air-gapped - a natural fit for a JVM shop that already runs its own services. The open-source edition is a real product: flag management, gradual rollouts, kill switches, canary. The catch is the OSS-versus-Enterprise line - RBAC, SSO/SAML and SCIM are all gated to paid tiers, and there is no read-only seat, so cost climbs once non-engineers need access. If your org mandates SSO, price the Enterprise tier first.

If you want cheap open source with less operational weight: Flagsmith. BSD-3-Clause, a Java SDK, and the cheapest paid cloud entry here at $40/mo annual. It bills on requests, so there is no MAU trap. The OSS self-host is free but runs a Django and Postgres stack - real DevOps work - so many JVM teams just take the cheap cloud tier.

If you want flat, predictable pricing: ConfigCat. A Java SDK and no per-seat or per-MAU fees at all - MAUs, contexts and flag reads are unlimited on every tier including Free. You pay by config-download volume. The Spring-specific watch-out: a client polling on a short interval across many instances drives download volume and can push you across a tier. Cache aggressively and use the SDK proxy.

Step 5: Wire it in safely

Whichever you pick, these hold in any Spring service:

  1. One client, as a singleton bean. Never build a client per request - it defeats local evaluation and floods the network.
  2. Always pass a default value so a service outage falls back to safe behavior.
  3. Use a stable user key so percentage rollouts are deterministic across requests for the same user.
  4. Close the client on shutdown via destroyMethod = "close" so the refresh thread stops cleanly.
  5. Delete stale flags. A flag at 100 percent for a quarter is debt - our how to clean up feature flags routine keeps the code honest.

So which one?

  • A toggle you change only at deploy time - stay in Spring with @ConfigurationProperties and @ConditionalOnProperty. No dependency needed.
  • You want the deepest platform and can absorb usage pricing - LaunchDarkly.
  • You want to self-host on your own JVM infra - Unleash, or Flagsmith for cheaper cloud and a request meter.
  • You want flat pricing with no per-MAU surprise - ConfigCat, and cache your polling.

The Java SDK is rarely the deciding factor - all four are solid on the JVM. The decision is pricing model and self-host. Working in Go too? The Go version of this guide covers the same platforms with idiomatic Go code.


Tool facts and pricing verified against each vendor’s site on 26 July 2026. Code samples are illustrative Java/Spring patterns - check each SDK’s docs for exact method signatures. Contract figures are from Vendr’s third-party buyer data and attributed as such.

Frequently Asked Questions

What is the best feature flag library for Java?

It depends on the constraint. LaunchDarkly has a Java SDK and the deepest tooling, at usage-based pricing. Unleash (AGPL-3.0) and Flagsmith (BSD-3-Clause) both ship Java SDKs and let you self-host. ConfigCat has a Java SDK with flat, no-per-MAU pricing. For a single toggle in Spring, a @ConfigurationProperties bean backed by application.yml needs no library at all - use that until you need runtime changes or targeting.

How do you implement feature flags in Spring Boot?

Two levels. For static toggles, bind a property from application.yml to a @ConfigurationProperties bean and read it, or gate a bean with @ConditionalOnProperty. For dynamic flags you can change without a redeploy, initialize a feature-flag SDK client as a Spring @Bean singleton, inject it into your services, and evaluate per request with a user key. The SDK caches rules in memory so checks stay fast.

Can Spring do feature flags without an external service?

Yes, for simple cases. Spring's @ConditionalOnProperty and @ConfigurationProperties let you toggle beans and behavior from configuration with zero dependencies. The limit is that changing a value needs a restart or a Spring Cloud Config refresh, and you get no per-user targeting, gradual rollout or audit trail. Once you need those, an SDK earns its place.

Do feature flag checks slow down a Java service?

Not meaningfully if the SDK evaluates locally, which the major ones do. The client caches flag rules in memory at startup and decides in microseconds - a flag check is a map lookup, not an HTTP call. Initialize the client once as a singleton bean and reuse it. The only network activity is a background thread refreshing rules, off the request path.

Explore More

Free Newsletter

Get the Feature Flags Newsletter

Platform benchmarks, real pricing data and progressive delivery practice. No spam.

Free. Unsubscribe any time. See our privacy policy.

Related Articles