Create your own
Lesson illustration

Implementing Feature Flags in Spring Boot

Hello! Welcome back.

In our last lesson, we explored how to perform zero-downtime database migrations using the expand-contract pattern. We briefly touched on using feature flags as a safety mechanism during those migrations. Today, we're going to dive deep into that concept and explore its full power.

Your learning outcome for this lesson is to implement feature flags within a Spring Boot application to decouple feature releases from deployments. This is a fundamental technique in modern software delivery, enabling practices like canary releases, A/B testing, and trunk-based development. Mastering feature flags is crucial for building robust, production-ready systems and is a common topic in senior engineering interviews.

We'll cover the core theory, different types of flags, simple implementations in Spring Boot, and the architectural patterns used in large-scale production environments.

1. Decoupling Deployment from Release

At its core, a feature flag system separates the act of deploying code from the act of releasing a feature to users. This might sound simple, but it's a profound shift in how we deliver software.

Difference Between Deployment and Feature Release
This diagram illustrates the key concept: 'Deployment' is the technical process of getting new code into a production environment. 'Release' is the business decision to make a feature available to end-users. Feature flags are the mechanism that controls the second part.

This decoupling gives us immense power:

  • Risk Mitigation: Deploy new, high-risk code to production but keep it turned "off". You can then enable it for internal testers or a small percentage of users to validate its stability before a full rollout.
  • Continuous Deployment: Teams can merge and deploy code to the main branch continuously, even if features are incomplete. The unfinished work simply sits behind a disabled flag.
  • Operational Control: Use flags as "kill switches" to disable non-essential, performance-intensive features during periods of high load.

To get a comprehensive overview of the philosophy and various applications of this technique, Martin Fowler's article is the definitive guide.

Feature Toggles (aka Feature Flags)

Let's start with the foundational concepts. The article 'Feature Toggles (aka Feature Flags)' by Pete Hodgson from Martin Fowler's website provides an excellent narrative and conceptual background.

Please read the introduction and the 'A Toggling Tale' section. This will walk you through a story of how a feature flag evolves from a simple variable to a dynamic tool for canary releases and A/B testing.

2. Categories of Feature Toggles

Not all feature flags are the same. Understanding their purpose helps you choose the right implementation and management strategy. In an interview, discussing the different categories shows a deeper, more nuanced understanding.

The Martin Fowler article you just started reading categorizes them based on longevity and dynamism. Let's focus on the four main types:

  • Release Toggles: These are used to hide incomplete features in a production environment, enabling trunk-based development. They are short-lived and should be removed once the feature is fully released.
  • Experiment Toggles (A/B Tests): Used to test different versions of a feature with different user cohorts to see which performs better against a business metric. They are dynamic (per-user) and exist for the duration of the experiment.
  • Ops Toggles: Used as "kill switches" to control the operational behavior of your system. For example, disabling a computationally expensive feature during a traffic spike. They can be long-lived and must be very dynamic.
  • Permissioning Toggles: Used to control which users get access to certain features, such as premium features for paying customers or beta features for internal users. These are often long-lived and highly dynamic.

Feature Toggles (aka Feature Flags)

To solidify your understanding of these categories, please continue with the same article.

Read the section 'Categories of toggles'. Pay close attention to the descriptions of Release, Experiment, Ops, and Permissioning Toggles and the two dimensions used to categorize them: longevity and dynamism.

Test your understanding!

Your team is developing a new, resource-intensive recommendation algorithm. The product manager is worried it might slow down the homepage during peak holiday shopping season. What category of feature toggle would be most appropriate to manage this risk after the feature is launched, and why?

Show answer

An Ops Toggle would be the most appropriate choice. Its purpose is to allow system operators to quickly disable or degrade functionality to maintain system stability. In this case, if the homepage slows down, an operator could flip the Ops Toggle to turn off the new algorithm and revert to a simpler, less intensive one (or disable the recommendations panel entirely), thus protecting the core user experience. This toggle would likely be long-lived.

3. Implementing Feature Flags in Spring Boot

Now, let's get practical. Given your experience with Spring Boot, you'll find that implementing simple, static feature flags is straightforward.

3.1. The Simplest Approach: @ConditionalOnProperty

For application-level flags, especially short-lived Release Toggles, you can use Spring's built-in conditional configuration. This is great for enabling or disabling entire components or configurations.

Let's say we're implementing a new ExperimentalSearchService to replace the old DefaultSearchService.

We can define our beans like this:

@Configuration
public class SearchServiceConfig {

    @Bean
    @ConditionalOnProperty(name = "features.search.use-experimental", havingValue = "false", matchIfMissing = true)
    public SearchService defaultSearchService() {
        return new DefaultSearchService();
    }

    @Bean
    @ConditionalOnProperty(name = "features.search.use-experimental", havingValue = "true")
    public SearchService experimentalSearchService() {
        return new ExperimentalSearchService();
    }
}

And control this with a simple property in application.yml:

features:
  search:
    use-experimental: true # Set to true to enable the new service
  • @ConditionalOnProperty(name = ..., havingValue = "true"): This bean is created only if the property features.search.use-experimental is present and set to true.
  • matchIfMissing = true: This ensures the defaultSearchService is our default bean if the property isn't defined at all.

3.2. A Cleaner Approach: @ConfigurationProperties

As the number of flags grows, managing them via individual @ConditionalOnProperty checks can get messy. A cleaner way is to group them into a dedicated configuration properties class.

@Component
@ConfigurationProperties(prefix = "features")
public class FeatureFlags {

    private final Search search = new Search();

    public Search getSearch() {
        return search;
    }

    // Inner class for better organization
    public static class Search {
        private boolean useExperimental;

        public boolean isUseExperimental() {
            return useExperimental;
        }

        public void setUseExperimental(boolean useExperimental) {
            this.useExperimental = useExperimental;
        }
    }
}

You can then inject this FeatureFlags bean anywhere in your application and use a standard if statement:

@Service
public class SomeOtherService {

    private final SearchService searchService;

    @Autowired
    public SomeOtherService(FeatureFlags featureFlags) {
        if (featureFlags.getSearch().isUseExperimental()) {
            this.searchService = new ExperimentalSearchService();
        } else {
            this.searchService = new DefaultSearchService();
        }
    }
    // ...
}

This second approach is often more flexible, especially when you need to toggle a piece of logic within a method rather than swapping out an entire bean.

Feature Flags with Spring

The Baeldung article 'Feature Flags with Spring' provides clear, concise code examples for these patterns.

Please read sections 3.1, 3.2, and 3.3. They cover 'Feature Flags Using Custom Properties' and 'Using @ConfigurationProperties'. You can skip the part about Spring Profiles as the custom properties approach is more explicit and scalable for feature flags.

4. Production-Ready Feature Flag Architectures

Using application.yml is great for simple cases, but it has a major limitation: changing a flag requires a redeployment or restart. This isn't suitable for Ops, Experiment, or Permissioning toggles that need to be dynamic.

Production-grade systems use dedicated feature flag management platforms. These can be:

  1. Libraries: Embedded in your application, like Togglz. They often come with an admin console and can store flag states in a database.
  2. Services: Centralized servers that your microservices communicate with, such as the open-source Unleash or commercial products like LaunchDarkly.

The service-based approach is common in microservice architectures.

Unleash Feature Flag Integration with Spring Boot
This diagram shows a typical architecture using a feature flag service. The Spring Boot application includes an SDK that polls the Unleash server for flag configurations. The SDK caches these flags locally, so checking a flag is extremely fast and doesn't require a network call for every request. This allows for centralized management and dynamic, near-instantaneous updates across your entire fleet of services.

This architecture allows for advanced features like:

  • Percentage-based rollouts (Canary Releases)
  • User-specific targeting (e.g., "enable for users in Germany")
  • An audit log of who changed which flag and when.

While we won't implement a full Unleash integration, understanding this architecture is vital for system design interview questions.

Finally, long-lived feature flags, especially those with complex if/else logic scattered throughout the code, can become a maintenance nightmare.

Feature Toggles (aka Feature Flags)

For long-lived flags, it's critical to write clean, maintainable code. The Martin Fowler article offers excellent advice on this.

Please read the sections 'Implementation Techniques' and 'Managing the carrying cost of Feature Toggles'. Focus on the concepts of 'Inversion of Decision' and using the Strategy Pattern to avoid conditionals. Also, absorb the idea that feature flags are a form of technical debt that must be proactively managed and removed.

5. Conclusion and Interview Preparation

Today we've seen how feature flags are a powerful tool for decoupling deployment from release, managing risk, and enabling modern CI/CD practices.

Key Takeaways:

  • Core Concept: Separate deploying code from releasing features.
  • Categorization: Different toggles (Release, Ops, Experiment, Permissioning) have different lifecycles and require different management strategies.
  • Simple Implementation: Use Spring Boot's @ConditionalOnProperty or @ConfigurationProperties for static, application-level flags.
  • Production Architecture: For dynamic control, use a dedicated library (Togglz) or a centralized service (Unleash, LaunchDarkly). The service-based model is ideal for microservices.
  • Technical Debt: Release Toggles are temporary and must be cleaned up to avoid code rot. Treat them as inventory with a carrying cost.
Senior Engineer Interview Question

"You are tasked with rolling out a new, high-risk integration with a third-party payment provider. You need to verify it works correctly in production with live traffic before switching all users over. How would you use feature flags to manage this process safely, and what kind of architecture would you propose for managing the flags themselves?"

Show detailed answer

"I would use a multi-phased approach with feature flags to de-risk this rollout.

Phase 1: Release Toggle & Internal Testing
First, I'd wrap the new payment provider logic behind a Release Toggle. Initially, this flag would be 'off' for everyone. Once deployed, we would turn it 'on' only for internal test users. This allows us to perform end-to-end validation in the production environment without impacting any real customers.

Phase 2: Canary Release
After validating the integration internally, I would evolve the flag into an Experiment Toggle for a canary release. I would configure it to enable the new payment provider for a small percentage of users, say 1%. We would closely monitor business metrics (e.g., payment success rate, latency) and technical metrics (errors, CPU/memory usage) for this cohort compared to the 99% still on the old provider. We'd gradually increase the percentage (5%, 20%, 50%) as we gain confidence.

Phase 3: Full Release & Cleanup
Once we reach 100% and the new provider is stable, the old payment provider code can be deprecated. The feature flag has served its purpose as a release mechanism, and we must schedule technical debt work to remove the flag and the old code path entirely.

Phase 4: Operational Safety
Finally, I would leave a permanent Ops Toggle (a 'kill switch') in place. If the new provider experiences an outage, this flag would allow us to instantly revert all traffic back to a fallback provider (or the old one, if kept as a standby) without a deployment, ensuring business continuity.

Proposed Architecture:
For managing these dynamic flags, a simple properties file is insufficient. I would propose using a centralized feature flag service like Unleash or LaunchDarkly. Our microservices would integrate with this service via an SDK. This architecture provides a central UI to manage flags, supports percentage-based rollouts, offers an audit trail, and allows for near-instantaneous changes without restarting services, which is critical for a safe and controlled rollout of this nature."

In our final module, we'll zoom out from the implementation details of individual services to the broader system. Our next lesson will be on how to decompose a complex system into microservices by applying the bounded context pattern, a cornerstone of microservice architecture and system design interviews.

Can't find a good explanation? Sign up and we'll make it for you

Sign up