Applications need the flexibility to adjust to changing requirements while they’re running. Restarting a service every time a property changes creates downtime and interruptions, which is a problem in environments where uptime is important. Spring Boot with Spring Cloud Config makes it possible to reload property values on the fly so that updates take effect without stopping the service. It works by separating configuration from code, keeping it in a central location, and giving the application a way to refresh its internal state while it continues to run.
How Dynamic Property Reload Works
Dynamic property reload in Spring Boot with Spring Cloud Config builds on a chain of ideas that connect external configuration, the internal environment model, and bean lifecycle management. Each layer has its job, and together they make it possible to apply new values without restarting the service.
Configuration Source with the Config Server
The foundation is the Spring Cloud Config server, which delivers configuration values over HTTP to client services. Instead of repeating the same application.yml
file in every service, you maintain a single copy in a shared repository. Most setups use Git as the backend because it already provides version history and simple updates. The config server exposes endpoints like /application/default
or /myservice/dev
that return the properties needed for that client.
Clients connect through Spring Boot’s Config Data import during startup. Setting spring.config.import
to configserver:
pulls from the Config Server before the application context is built. This means that values from the config server are available early enough to influence how the service initializes. When a new property is committed to the repository, the server presents it right away to any client that requests it.
Updating a file in the repository with custom.message=Welcome
immediately makes the new value visible through the server, forming the foundation of reload.
The Spring Environment
Every running Spring Boot application maintains its configuration in an Environment
object. The Environment
is made up of multiple property sources, ranging from operating system variables and command-line arguments to local files and remote configuration from the config server. When a property is requested with @Value
or @ConfigurationProperties
, Spring resolves the value from the environment.
Because the environment layers property sources, it can be refreshed without tearing down the whole application. When a refresh event occurs, the environment is updated with the latest values from the config server, and beans can be re-created with those values in place.
A bean like this will keep the old value forever without refresh support. With refresh in place, the environment gets new values and rebuilds beans that depend on them.
Refreshing Beans with @RefreshScope
Normally beans are created once and live until shutdown. @RefreshScope
changes that pattern by telling Spring to discard the bean when a refresh event occurs and build a new one with updated values from the environment.
After committing a change to greeting.message
in the repository and refreshing the service, the controller now responds with the updated message. The rest of the application keeps running without interruption.
A second example shows how multiple related properties can update together:
Both values change at refresh time, so connectivity details can be adjusted on the fly.
How the Refresh Trigger Works
Changing a property in the repository doesn’t push it into a client automatically. The client must be told to reload its environment. Spring Cloud Context exposes the /actuator/refresh
endpoint. Add the Spring Cloud bits and expose the endpoint before sending a POST
to it. When called, the application pulls the latest configuration, updates its environment, and rebuilds refresh-scoped beans.
At that point, any bean with @RefreshScope
is replaced and recreated with fresh values. For systems with many services, Spring Cloud Bus builds on the same idea but spreads the refresh signal through a message broker such as RabbitMQ or Kafka. That lets one refresh action reach all subscribed services without manual calls to each.
Rebinding with @ConfigurationProperties
Groups of settings are easier to work with through @ConfigurationProperties
. A dedicated class maps to a prefix, keeping related values together in a structured way. Combined with @RefreshScope
, the entire class is rebuilt on refresh.
When those values change and a refresh runs, Spring re-binds the @ConfigurationProperties
bean to the new values. If you want a brand new instance instead of simply re-binding, you can mark the @ConfigurationProperties
class with @RefreshScope
. Constructor-bound properties will refresh as long as the bean itself is placed in refresh scope, but Java record
based properties can’t be refreshed at all.
This keeps property groups consistent and avoids having to manage updates across many scattered @Value
fields.
Thread Safety During Bean Recreation
Refresh events don’t mutate beans in place. Instead, Spring removes the old bean and replaces it with a fresh instance. Any ongoing request that already holds a reference to the old bean finishes with it, while new requests get the updated one. This keeps refresh safe from concurrency problems and provides predictable behavior during the transition.
When the timeout property changes, the bean is rebuilt. Active calls continue with the old instance, and future calls go through the new one. The refresh is managed by Spring’s bean factory, which handles the sequence in a controlled way.
Limitations of Dynamic Reload
Some properties can’t be refreshed at runtime because the resources they connect to don’t support swapping values without a restart. Database URLs, server ports, and certain core infrastructure values usually require the entire service to restart so the new resources can be properly initialized. Properties that work best with refresh are those that adjust behavior rather than rebuild core resources. Examples include feature flags, timeout values, and service endpoints. Developers often choose carefully which beans to mark with @RefreshScope
so that refresh events stay safe and effective.
Changing a datasource URL like this won’t take effect through refresh alone. The connection pool holds onto the original configuration, and a full restart is needed.
Practical Use of Dynamic Property Reload
Learning the mechanics is one thing, but seeing them applied in a service brings the concept to life. A config server holds the properties, the client connects to it, and refresh events make the changes visible. With those pieces working together, you can shift configuration without restarting services.
Setting Up a Config Server
A Spring Cloud Config server sits between your services and the configuration repository. The server itself is just a Spring Boot application with the spring-cloud-config-server
dependency. After that’s added, marking the main class with @EnableConfigServer
turns it into a provider of configuration values.
The next step is telling the server where to pull configuration from. Git is common because it brings version history and a simple way to change values, though file systems and databases are also supported.
With this running, a client fetches configuration from endpoints like http://localhost:8888/{application}/{profile}
(optionally with /{label}
).
Configuring a Client Service
Modern Spring Boot clients bind to Config Server through the Config Data API. Use application.yml
and set spring.config.import
to pull from the server during startup. Doing this means remote configuration is in place before the context is built.
When the service starts, it requests values under orderservice
. Profiles such as dev
or prod
can be applied for different environments.
Changing order.limit
in the repository and refreshing the service lets the limit adapt on the fly, which is especially helpful for rules that evolve quickly.
Testing Automatic Refresh with Spring Cloud Bus
Refreshing one service at a time is fine for small systems, but large environments need something broader. Spring Cloud Bus connects services through a broker such as RabbitMQ or Kafka and carries refresh events across all of them.
Expose the bus endpoint and POST to /actuator/busrefresh
to clear the RefreshScope
cache and rebind configuration across services.
Monitoring Refresh Events
To confirm a refresh, call POST /actuator/refresh
and review its response, then check /actuator/configprops
to see the re-bound values. On Spring Boot 3, set a show-values property during testing so values aren’t masked. The beans endpoint only shows definitions and scopes, so it isn’t a reliable check for replacement.
With those properties in place, you can actually see the values when you call the endpoints. The refresh process itself is triggered through a simple HTTP request:
The refresh response returns the collection of property keys that changed. Beans annotated with @RefreshScope
are then rebuilt, and @ConfigurationProperties
beans are rebound based on those changed keys
Logs are another valuable tool. Logging when a refresh occurs gives operators a trail of when configuration was updated and what properties changed. This helps tie behavior in production back to specific edits in the repository. For deeper inspection, the /actuator/env
endpoint shows all property sources at the moment. Comparing before and after snapshots proves that updates were applied and are now active within the service.
Conclusion
Dynamic property reload with Spring Boot and Spring Cloud Config relies on the config server as a central source, the environment for managing values, and refresh-scoped beans that rebuild with updated data. Actuator endpoints or bus events carry the trigger, and the service keeps running while new configuration is applied. The mechanics work together to let applications stay responsive to change without being forced into downtime.
