Spring Boot
ConditionalOnProperty
ConditionalOnExpression
Java Programming
Application Configuration

How to check two condition while using ConditionalOnProperty or ConditionalOnExpression

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Spring Boot often needs more than one property check before creating a bean. The right annotation depends on the shape of the rule: use @ConditionalOnProperty for straightforward property matching, @ConditionalOnExpression for simple boolean combinations, and a custom Condition when the logic becomes complex enough that annotations start hiding the real behavior.

@ConditionalOnProperty Handles Simple AND Checks

When several properties must all be present and all match the same expected value, @ConditionalOnProperty is the clearest option.

java
1import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2import org.springframework.context.annotation.Bean;
3import org.springframework.context.annotation.Configuration;
4
5@Configuration
6@ConditionalOnProperty(
7        prefix = "app.feature",
8        name = {"enabled", "audit"},
9        havingValue = "true"
10)
11public class FeatureConfig {
12
13    @Bean
14    public FeatureService featureService() {
15        return new FeatureService();
16    }
17}

This condition matches only when both app.feature.enabled=true and app.feature.audit=true.

Use matchIfMissing Deliberately

By default, @ConditionalOnProperty requires the property to exist. If missing properties should behave as enabled, you can change that explicitly.

java
1@ConditionalOnProperty(
2        prefix = "app.cache",
3        name = "enabled",
4        havingValue = "true",
5        matchIfMissing = true
6)

This is powerful, but it changes startup behavior in a way that is easy to forget later. Use it only when the default should really be opt-in by omission.

@ConditionalOnExpression for Mixed Boolean Logic

If your rule is more like "enabled and one of two modes is active," @ConditionalOnExpression is usually the simplest annotation-based choice.

java
1import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
2import org.springframework.context.annotation.Bean;
3import org.springframework.context.annotation.Configuration;
4
5@Configuration
6@ConditionalOnExpression(
7        "'${app.feature.enabled:false}' == 'true' " +
8        "and ('${app.mode:standard}' == 'standard' or '${app.mode:standard}' == 'safe')"
9)
10public class AdvancedFeatureConfig {
11
12    @Bean
13    public FeatureService featureService() {
14        return new FeatureService();
15    }
16}

This works, but it is less readable than @ConditionalOnProperty. SpEL expressions also become harder to debug as the rule grows.

When a Custom Condition Is Better

Once the condition involves multiple branches, parsing, or reusable logic, write a custom Condition. That keeps the rule in normal Java code instead of embedding it into an annotation string.

java
1import org.springframework.context.annotation.Condition;
2import org.springframework.context.annotation.ConditionContext;
3import org.springframework.core.type.AnnotatedTypeMetadata;
4
5public class FeatureEnabledCondition implements Condition {
6    @Override
7    public boolean matches(
8            ConditionContext context,
9            AnnotatedTypeMetadata metadata) {
10        String enabled = context.getEnvironment().getProperty("app.feature.enabled");
11        String mode = context.getEnvironment().getProperty("app.mode");
12        return "true".equalsIgnoreCase(enabled)
13                && ("standard".equalsIgnoreCase(mode) || "safe".equalsIgnoreCase(mode));
14    }
15}

Then apply it like this:

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Conditional;
3import org.springframework.context.annotation.Configuration;
4
5@Configuration
6@Conditional(FeatureEnabledCondition.class)
7public class FeatureConfig {
8
9    @Bean
10    public FeatureService featureService() {
11        return new FeatureService();
12    }
13}

This is more verbose, but it is also easier to test and maintain.

A Simple Decision Rule

Use this mental model:

  • same expected value across several properties: @ConditionalOnProperty
  • short boolean expression across a few properties: @ConditionalOnExpression
  • anything business-specific or complex: custom Condition

This keeps your configuration readable at startup time, which matters because conditional bean logic can be hard to trace once a project grows.

Common Pitfalls

The most common mistake is reaching for @ConditionalOnExpression too early. A short SpEL string looks compact, but it becomes hard to read and debug faster than most teams expect.

Another issue is forgetting that @ConditionalOnProperty with multiple name values behaves like an AND check for the same havingValue. It is not a general-purpose boolean expression language.

Developers also trip over quoting and default values inside SpEL placeholders. If a property is missing and you did not provide a safe default, the expression may not behave the way you think.

Finally, keep conditions about configuration, not application state. These annotations are for bean registration at startup, not for runtime feature toggling after the application is already running.

Summary

  • Use @ConditionalOnProperty for simple property presence or same-value AND checks.
  • Use @ConditionalOnExpression for short mixed boolean logic.
  • Use matchIfMissing only when a missing property should intentionally count as a match.
  • Write a custom Condition when the rule stops being readable as an annotation.
  • Keep startup conditions explicit so bean creation remains easy to reason about.

Course illustration
Course illustration

All Rights Reserved.