Config Server
When you run twenty services across three environments, copying property files everywhere is unmanageable. Spring Cloud Config Server centralizes configuration in one place — typically a git repository — and serves it to every service at startup, with runtime refresh and encryption built in. This page builds a server and wires up a client.
Why a config server
- Single source of truth. All configuration lives in one versioned repository.
- Audit and rollback. Git history shows who changed what, and reverting is a
git revert. - Environment overlays. Per-profile files (
-dev,-prod) layer cleanly. - Refresh without redeploy. Change config and refresh running services in place.
git repo (config)
│
▼
┌───────────────────┐ spring.config.import
│ Config Server │◄──────────────────────── orders-service
│ @EnableConfigServer│◄──────────────────────── inventory-service
└───────────────────┘◄──────────────────────── payments-service
The config server
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
# application.yml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/acme/config-repo
default-label: main
search-paths: '{application}' # optional per-service subfolders
The git repository layout
The server maps requests to files by application name and profile:
config-repo/
├── application.yml # shared defaults for ALL services
├── orders-service.yml # orders, all profiles
├── orders-service-dev.yml # orders, dev profile
└── inventory-service.yml
A client named orders-service running with profile dev receives application.yml + orders-service.yml + orders-service-dev.yml, merged with the most specific winning. You can verify directly over HTTP:
curl http://localhost:8888/orders-service/dev
Output:
{
"name": "orders-service",
"profiles": ["dev"],
"label": "main",
"propertySources": [
{ "name": "...orders-service-dev.yml", "source": { "server.port": 8081 } },
{ "name": "...orders-service.yml", "source": { "feature.flag": true } }
]
}
The client
Add the config client starter and tell Boot to import config from the server. As of Spring Boot 2.4+, the modern mechanism is spring.config.import, not the old bootstrap context.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
# orders-service application.yml
spring:
application:
name: orders-service # must match the file name in the repo
config:
import: "configserver:http://localhost:8888"
profiles:
active: dev
Note: The application name is what selects the right config file, so set
spring.application.namecorrectly. To fail fast if the server is unreachable, useimport: "configserver:..."(nooptional:prefix).
Runtime refresh
Beans annotated with @RefreshScope are recreated when configuration changes — no restart needed.
@RestController
@RefreshScope
public class FeatureController {
@Value("${feature.flag:false}")
private boolean featureFlag;
@GetMapping("/feature")
public boolean feature() { return featureFlag; }
}
Expose and trigger the Actuator refresh endpoint:
management:
endpoints:
web:
exposure:
include: refresh
# after committing a change to the config repo:
curl -X POST http://localhost:8081/actuator/refresh
Output:
["feature.flag"]
The response lists the property keys that changed. For fleet-wide refresh without hitting each instance, add Spring Cloud Bus (spring-cloud-starter-bus-amqp) so a single /actuator/busrefresh broadcasts the change over RabbitMQ or Kafka.
Encryption
Never commit plaintext secrets. The config server can decrypt values on the way out so clients only ever see clear text in memory.
# config server — symmetric key (use an asymmetric keystore in production)
encrypt:
key: ${ENCRYPT_KEY}
# encrypt a secret via the server's endpoint
curl http://localhost:8888/encrypt -d 's3cr3t-db-password'
# → a long cipher string
Store the cipher in the repo prefixed with {cipher}:
spring:
datasource:
password: '{cipher}AQB3f8...redacted...'
Tip: For real deployments prefer a dedicated secrets manager (HashiCorp Vault via
spring-cloud-starter-vault-config, or your cloud provider’s secret store) over committing even encrypted secrets to git.