Have you ever come across @Configuration or @Bean while developing with Spring Boot? “What’s the difference from @Component?” and “Where is the right place to use it?” — these are points that tend to cause confusion.

This article explains the role and usage of @Configuration / @Bean with concrete examples.


What is @Configuration?

@Configuration is an annotation that tells Spring: “This class is a configuration class.” Inside a configuration class, you define @Bean methods to assemble the objects (Beans) you want to register in the Spring container.

Think of @Configuration as providing a dedicated place to describe how Beans are created.


What is @Bean?

@Bean is an annotation placed on a method, and it registers the method’s return value as a Bean in the Spring container. While @Component says “attach this to a class to register the class itself as a Bean,” @Bean says “register the object returned by this method as a Bean” — that is the key difference.

Typical use cases where @Bean shines:

  • You want to register a class from an external library (one you didn’t write) as a Bean
  • The creation process is slightly complex and can’t be done with a simple new
  • You want to combine configuration values or dependent Beans during instantiation

Basic Usage (Example)

Say you want to register Clock, a class from an external library, as a Bean. Since you can’t attach @Component to that class, @Bean is the way to go.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Clock;

@Configuration
public class AppConfig {

    @Bean
    public Clock clock() {
        return Clock.systemDefaultZone();
    }
}

This registers Clock in the Spring container, making it available for DI from other classes.

import org.springframework.stereotype.Service;
import java.time.Clock;

@Service
public class TimeService {
    private final Clock clock;

    public TimeService(Clock clock) {
        this.clock = clock;
    }
}

Useful Techniques

Specifying a Bean Name

By default, the method name becomes the Bean name. If you want to be explicit, you can specify it like this:

@Bean("systemClock")
public Clock clock() {
    return Clock.systemDefaultZone();
}

Receiving Dependencies as @Bean Method Parameters (Very Handy)

A @Bean method can declare the Beans it needs as parameters, and Spring will resolve and inject them automatically.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyClient myClient(MyProperties props, Clock clock) {
        return new MyClient(props.getEndpoint(), clock);
    }
}

This is where the value of using @Configuration as “a place to wire Beans together” really shows.

Changing Scope (When Needed)

The default scope is singleton (one instance per application), but depending on the use case you may use prototype or others.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

@Bean
@Scope("prototype")
public SomeObject someObject() {
    return new SomeObject();
}

(That said, singleton covers the vast majority of typical business applications.)


Common Pitfalls

1) Behavioral Difference Due to @Configuration “Proxying”

A class annotated with @Configuration is internally proxied, which ensures that calls between @Bean methods return the same Bean instance managed by the container. As a result, code like the following does not create a new a() every time — it returns the same container-managed instance.

@Configuration
public class AppConfig {

    @Bean
    public A a() {
        return new A();
    }

    @Bean
    public B b() {
        return new B(a()); // calling a()
    }
}

Conversely, omitting @Configuration (or depending on configuration) changes this behavior and can lead to confusion. As a rule of thumb, “if you’re writing @Bean, just put it in a @Configuration class” will save you from a lot of surprises early on.

2) Can @Bean Be Used Without @Configuration?

The short answer is yes. However, there is a prerequisite.

Prerequisite: The Class Itself Must Be Under Spring Management

@Bean only makes sense when it is written inside a class that Spring picks up. In other words, as long as the class itself is registered as a Bean, @Bean will work without @Configuration:

  • The class has @Component
  • It is component-scanned under @SpringBootApplication (or imported via @Import)
  • It is explicitly loaded as a Java Config

Example: @Bean works inside a @Component class too.

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.time.Clock;

@Component
public class AppConfig {

    @Bean
    public Clock clock() {
        return Clock.systemDefaultZone();
    }
}

In this case, Clock is still registered as a Bean in the Spring container.

However, @Configuration Is Safer

When @Configuration is present, the configuration class runs in “full mode” (CGLIB proxy), which ensures that even when @Bean methods call each other, the same container-managed Bean is returned.

Without @Configuration (e.g., using only @Component), @Bean method calls are treated as plain method invocations, which can result in separate instances being created depending on the situation.

Therefore, when writing a configuration class, using @Configuration is the safe default.

3) Don’t Force @Bean Where @Component Is Sufficient

If you own the class, its instantiation is simple, and it can be component-scanned normally, @Component / @Service / @Repository etc. are perfectly fine. @Bean is most useful when “you can’t annotate the class directly” or “the creation logic is somewhat special.”


A Practical Decision Guide

When you’re unsure about the boundary between @Component and @Bean, the following table should help:

SituationRecommendationReason
Registering your own class as-is@Component familySimple and readable
Registering an instance of an external library@Configuration + @BeanCannot annotate the class directly
Creation requires conditional logic or config assembly@Configuration + @BeanInitialization logic is explicit
Defining multiple Beans of the same type for different uses@Bean + @QualifierSafe, name-based selection

Treating a configuration class as a “wiring diagram for dependent objects” gives it a clear role and keeps your design readable.

Tips for Easy Test Replacement

@Bean definitions work great with test substitutions. For example, if you define an external API client as a Bean, you can easily swap it out with @TestConfiguration or @MockBean.

@TestConfiguration
public class TestClientConfig {
    @Bean
    public ApiClient apiClient() {
        return new ApiClient("http://localhost:9999");
    }
}

Compared to directly new-ing production implementations, this approach makes switching between test and production environments much safer.

Operational Considerations

  • If specifying Bean names explicitly, establish a naming convention (e.g., xxxClient, xxxClock)
  • Avoid overusing conditional Beans (@ConditionalOnProperty, etc.)
  • If the dependency graph becomes complex, split the configuration class

Turning a configuration class into “a place to dump everything” makes it unreadable quickly — splitting by domain is an effective strategy.


Summary

  • @Configuration is “a configuration class where you centralize how Beans are created”
  • @Bean is “registers a method’s return value as a Bean in the Spring container”
  • @Bean is especially useful when you want to DI a class from an external library or when instantiation is complex
  • @Bean can be used without @Configuration (provided the class itself is under Spring management)
  • That said, when writing a configuration class, attaching @Configuration and using it consistently is the safer, less error-prone approach