When developing with Spring Boot, you often use @Bean. And one subtle thing that tends to puzzle developers is: “Should I give this @Bean a name? Or just leave it alone?”

In this article, we’ll organize—from a practical standpoint—what the @Bean name is used for, when you should specify it explicitly, and even how the precedence works (which one gets picked) when multiple Beans exist.

What is the “name” of @Bean?

In Spring, every Bean registered in the container has a “Bean name (identifier).” For @Bean, this Bean name shows up mainly in the following situations:

  • Determining which Bean to inject when multiple Beans of the same type exist
  • Name-based injection like @Qualifier / @Resource
  • Conditional Bean registration (@ConditionalOnBean(name=...), etc.)
  • Bean overriding or conflict detection

In other words, the name is “a key to identify a Bean.”

Default naming rule

When you don’t specify a name with @Bean, the Bean name becomes the “method name.”

@Configuration
public class MyConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

In this example, the Bean name is myService.

The rule is simple—method name = Bean name—so being aware that “even when you think you haven’t given it a name, it has one” helps you avoid pitfalls.

How to specify names (explicit names and aliases)

Specifying a single name

@Configuration
public class MyConfig {

    @Bean("mainService")
    public MyService myService() {
        return new MyService();
    }
}

@Bean("...") is shorthand for @Bean(name="...")—they mean the same thing.

Adding aliases (alternative names)

You can also give a single Bean multiple names.

@Configuration
public class MyConfig {

    @Bean({"dataSource", "readDataSource"})
    public DataSource dataSource() {
        // ...
        return /* DataSource */;
    }
}

In this case, the same Bean can be referenced by both dataSource and readDataSource. (However, overusing this makes code harder to read, so use it only when needed.)

When should you specify a name?

The bottom line: in most cases, leaving it alone (= using the method name) is enough. However, in the following situations, there’s significant benefit to specifying a name explicitly.

When multiple @Beans of the same type exist

For example, when you want to create two kinds of MyClient.

@Configuration
public class ClientConfig {

    @Bean("userClient")
    public MyClient userClient() {
        return new MyClient("https://user-api.example");
    }

    @Bean("billingClient")
    public MyClient billingClient() {
        return new MyClient("https://billing-api.example");
    }
}

When Beans of the same type serve different purposes, “expressing intent through names” makes things easier later. (You can also express it via method names, but if you plan to use @Qualifier, the intent becomes clearer.)

When you want to specify the target using @Qualifier / @Resource at the injection site

As we’ll discuss later, names are a very powerful means of resolving injection. If your intent is “this injection must be this specific Bean,” giving it a name is safer.

When you want to reference a “name” in a Condition

Even within Spring Boot itself, there are many cases where AutoConfiguration branches based on Bean names. For a complete picture of what AutoConfiguration looks at to register/skip Beans, see Understanding How Spring Boot AutoConfiguration Works.

There are cases where Bean names are used in Spring Boot’s Auto Configuration or your own conditional logic.

  • @ConditionalOnBean(name = "xxx")
  • @ConditionalOnMissingBean(name = "xxx")

In situations like this where “the name becomes the API,” it’s safer to specify it explicitly.

When you want to distinguish from Beans provided by external libraries

There are situations where you define a Bean of the same type as one provided by an external library, but on your own. In that case, separating the names makes injection easier to read.

Injection precedence (@Qualifier / @Primary / parameter names, etc.)

This is the trickiest part. The key point is: “after collecting candidates by type, how do you narrow it down to one?”

First, the basics: @Autowired starts from “type”

@Service
public class MyUseCase {

    private final MyClient client;

    public MyUseCase(MyClient client) {
        this.client = client;
    }
}

If there’s only one Bean of type MyClient, this works. But if there are multiple, Spring can’t decide which to inject and throws an error.

@Qualifier takes top priority (in practice, this is the strongest)

@Service
public class MyUseCase {

    private final MyClient client;

    public MyUseCase(@Qualifier("billingClient") MyClient client) {
        this.client = client;
    }
}

@Qualifier("billingClient") is a specification to “narrow down the candidates.” No matter how many Beans of the same type exist, you can pinpoint one by name (or Qualifier).

@Primary is effective when you want to decide “the default one”

@Configuration
public class ClientConfig {

    @Bean
    @Primary
    public MyClient primaryClient() {
        return new MyClient("https://default.example");
    }

    @Bean("billingClient")
    public MyClient billingClient() {
        return new MyClient("https://billing-api.example");
    }
}

@Primary is a statement of intent: “if there are multiple candidates, use this one by default.” However, if the injection site has @Qualifier, that takes precedence. (It makes it easy to design with “this is the default, only specify with Qualifier in special cases.”)

Parameter names (variable names) can serve as hints

When multiple Beans of a type exist, Spring can sometimes resolve injection if the injection point’s name (field name, argument name) matches a Bean name.

@Service
public class MyUseCase {

    private final MyClient billingClient;

    public MyUseCase(MyClient billingClient) {
        this.billingClient = billingClient;
    }
}

If a Bean named billingClient exists, this may resolve correctly. However, since compile settings and circumstances can affect how this is read, in practice, “if you want to be explicit, use @Qualifier” is the more robust approach.

@Resource is “name-first” injection

@Resource basically resolves by name.

@Service
public class MyUseCase {

    @Resource(name = "billingClient")
    private MyClient client;
}

The feel is different from @Autowired, so mixing them can be confusing. (If you use it, it’s best to commit to using it as “name-based injection.”)

”Name collisions” and notes on Bean overriding

@Bean names must be unique. If multiple Bean definitions with the same name are registered, Spring Boot will, by default, throw an error (overriding is disabled by default).

For example, if you define a method with the same name in a different configuration class, you’ll get a collision.

@Configuration
public class AConfig {
    @Bean
    public MyService myService() { return new MyService(); }
}

@Configuration
public class BConfig {
    @Bean
    public MyService myService() { return new MyService(); }
}

It’s not the “type” but the “name” that’s the same, so this is where accidents happen.

The simplest way to avoid this accident is to “change the name (or method name) if the intent is different.”

If you absolutely must override, you can allow it with spring.main.allow-bean-definition-overriding=true, but in production this is a breeding ground for bugs, so it’s safer to leave it OFF by default.

Hard-coding strings like @Qualifier("billingClient") makes typos and rename accidents more likely. In practice, it’s safer to define Bean names as constants and reference them.

public final class BeanNames {
    private BeanNames() {}

    public static final String BILLING_CLIENT = "billingClient";
    public static final String USER_CLIENT = "userClient";
}
@Configuration
public class ClientConfig {

    @Bean(BeanNames.USER_CLIENT)
    public MyClient userClient() {
        return new MyClient("https://user-api.example");
    }

    @Bean(BeanNames.BILLING_CLIENT)
    public MyClient billingClient() {
        return new MyClient("https://billing-api.example");
    }
}
@Service
public class MyUseCase {

    private final MyClient client;

    public MyUseCase(@Qualifier(BeanNames.BILLING_CLIENT) MyClient client) {
        this.client = client;
    }
}

With this approach, when you need to change a Bean name, you can consolidate the changes to a single place (the constant).

Summary

  • A @Bean’s Bean name defaults to the “method name”
  • Typical cases where you should specify a name: “multiple Beans of the same type,” “you want to inject by name,” “you want to reference the name in a condition”
  • Injection precedence, roughly speaking:
    • @Qualifier (the strongest, most specific designation)
    • @Primary (designates one default)
    • Name matching (may be resolved by parameter name, etc.)
  • Name collisions tend to cause startup errors in Spring Boot, so watch out for same-named @Beans

While @Bean names usually work without thought, they “suddenly become very important the moment multiple Beans appear.”

If you’re unsure, base your design on these three:

  • “Default is @Primary”
  • “Use @Qualifier where you want to be explicit”
  • “Avoid hardcoded strings—define them as constants”

These three axes will make your design more stable.