Introduction
Managing configuration across distributed Spring Boot microservices efficiently is challenging, especially when multiple environments, security concerns, and dynamic updates are involved. Spring Cloud Config provides a centralized, version-controlled, and flexible configuration management solution with native support for Git-backed repositories.
This guide is a comprehensive, practical walkthrough to set up a Spring Cloud Config Server and a Spring Boot client that fetches configuration dynamically from Git, supports runtime refreshes, and incorporates secure practices for production readiness.
Intended Reader
This guide targets Java developers, DevOps engineers, and architects working with Spring Boot microservices who want to implement centralized configuration management using Spring Cloud Config with Git as backend.
Concrete Outcome
By following this guide, you will be able to:
- Set up a Spring Cloud Config Server with Git backend
- Structure your configuration repository for environment and service specificity
- Build a Spring Boot client that consumes this config dynamically
- Refresh configuration at runtime without restarting services
- Secure secrets using encryption and best practices
- Understand failure modes, operational considerations, and verification
Prerequisites
- JDK 17 or newer
- Basic familiarity with Spring Boot, Git, Maven/Gradle
- Development environment configured for Spring Boot 3.x and Spring Cloud 2022.x
Version Assumptions
- Spring Boot 3.x
- Spring Cloud 2022.x (Config Server 4.x compatible)
When and Why Use Spring Cloud Config?
Centralized configuration is critical for microservices to avoid config drift, improve change visibility, and ease system administration.
When to Use
- Your architecture includes multiple services sharing varying configuration
- Environment-specific configuration (dev, test, prod) is needed
- You want runtime configuration refresh without downtime
- Version control and audit trail of configuration is important
- You need centralized secrets management with encryption
When Not to Use
- Monolithic Spring Boot apps with minimal dynamic configuration
- When you already run Kubernetes with ConfigMaps and Secrets fully managing config
- If your organization uses alternative centralized config services (Consul, ZooKeeper)
Alternatives & Trade-offs
| Approach | Pros | Cons |
|---|---|---|
| Local files | Simple, no network dependence | Difficult to maintain at scale |
| Kubernetes Config | Native to Kubernetes, secure | Kubernetes lock-in, less flexible |
| Consul/ZooKeeper | Highly available, dynamic | Adds operational complexity |
| Spring Cloud Config (Git) | Versioned, familiar, auditable | Requires Git management, no push update triggers |
Architecture Overview
Spring Cloud Config architecture consists of:
- Config Server: Spring Boot app that exposes REST endpoints to serve configuration by application and profile
- Config Repository: Git repository containing property or YAML files organized by app and profile
- Config Client: Spring Boot microservice that fetches and refreshes configuration
Config files resolution hierarchy:
application.yml
application-{profile}.yml
{application}.yml
{application}-{profile}.yml
Profiles control environment-specific overrides (e.g., dev, prod).
Step 1: Build the Spring Cloud Config Server
Project Setup
Use Spring Initializr (https://start.spring.io/) and create a Maven project with dependencies:
Spring Cloud Config ServerSpring Boot Actuator
Alternatively, add to pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
Enable Config Server
In src/main/java/com/example/configserver/ConfigServerApplication.java:
package com.example.configserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
@EnableConfigServer exposes endpoints like /application/{profile}.
Configure Git Repository Backend
Create src/main/resources/application.yml:
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-username/your-config-repo.git # replace with your repository
clone-on-start: true
default-label: main
management:
endpoints:
web:
exposure:
include: health,info
- The server listens on port 8888
- Cloning at startup improves response times
Step 2: Structure Your Configuration Repository
Repository Layout
Example Git repository config-repo structure:
config-repo/
application.yml
application-prod.yml
orderservice.yml
orderservice-prod.yml
paymentservice.yml
paymentservice-prod.yml
Sample config file: orderservice-prod.yml
server:
port: 8080
custom:
greeting: "Welcome to Order Service - Production"
Naming Conventions
application.yml: defaults common to all services and profilesapplication-{profile}.yml: profile-specific overrides{application}.yml: service specific defaults{application}-{profile}.yml: service and profile specific
Security Note
Avoid storing plaintext secrets in Git. Encrypt secrets or integrate with HashiCorp Vault (discussed later).
Step 3: Run and Verify the Config Server
Start your server:
mvn spring-boot:run
Verify it listens on port 8888:
curl http://localhost:8888/orderservice/prod
Expected output includes JSON with configuration properties merged and converted from YAML.
Step 4: Create and Configure a Spring Boot Config Client
Add Dependencies
In your client project’s pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Bootstrap Configuration
Create src/main/resources/bootstrap.yml (this loads earlier than application.yml):
spring:
application:
name: orderservice
cloud:
config:
uri: http://localhost:8888
fail-fast: true
management:
endpoints:
web:
exposure:
include: refresh,health,info
spring.application.namemust match config file names in Gitfail-fastcauses startup failure if the Config Server is unreachable- Exposes actuator endpoints necessary for refresh
Local Defaults with application.yml (optional)
server:
port: 8080
logging:
level:
root: INFO
Step 5: Enable Runtime Configuration Refresh
Annotate Beans with @RefreshScope
In your client, create a REST controller that responds with a config value:
package com.example.orderservice;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class GreetingController {
@Value("${custom.greeting:Hello default}")
private String greeting;
@GetMapping("/greet")
public String greet() {
return greeting;
}
}
The @RefreshScope tells Spring to reload this bean’s config when /actuator/refresh is called.
Trigger Refresh Manually
After updating the remote config (orderservice-prod.yml) and pushing to Git:
curl -X POST http://localhost:8080/actuator/refresh
This forces the client to fetch updated config without restarting.
Verify updated config by curling:
curl http://localhost:8080/greet
You should see the new greeting.
End-to-End Code Example
Config Server Application
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Client Greeting Controller
@RestController
@RefreshScope
public class GreetingController {
@Value("${custom.greeting:Hello default}")
private String greeting;
@GetMapping("/greet")
public String greet() {
return greeting;
}
}
How They Collaborate
- Config Server exposes configuration stored in Git.
- Client fetches configuration matching its app name and active profile.
- Controller reads the injected
custom.greetingproperty. - Refresh endpoint allows live config changes without restarts.
Verification Steps
- Start Config Server:
- Command:
mvn spring-boot:runin server project - Verify port 8888 active
- Test Config Server REST:
curl http://localhost:8888/orderservice/prod
Expect JSON response with merged properties.
- Start Client Service:
mvn spring-boot:runin client project- Verify port 8080 active
- Test client property endpoint:
curl http://localhost:8080/greet
Response: greeting configured in Git.
- Update Config: Modify
custom.greetingin Git repo and push changes.
- Refresh config dynamically:
curl -X POST http://localhost:8080/actuator/refresh
- Verify new value:
curl http://localhost:8080/greet
Response should reflect new greeting.
Production Failure Modes and Troubleshooting
| Issue | Cause | Resolution |
|---|---|---|
| Config Server fails to start | Incorrect Git repo URL or permissions | Verify URL, credentials, and network access |
| Client startup fail | Config Server unreachable; fail-fast enabled | Verify server availability; disable fail-fast to debug |
/actuator/refresh endpoint missing | Dependencies missing or endpoint not exposed | Add relevant dependencies and configure actuator exposure |
| Secrets show in logs or responses | No encryption configured | Implement encryption or Vault integration |
| Configs not updating | /actuator/refresh not called | Automate refresh via Spring Cloud Bus or manual trigger |
Logs on both server and client are critical for diagnosis.
Securing Your Configuration
Secrets Encryption
Avoid plaintext secrets in Git by:
- Using Spring Cloud Config Server's encryption support:
- Configure a Java keystore:
encrypt:
key-store:
location: classpath:/mykeys.jks
password: changeit
alias: mykey
secret: changeit
- Encrypt secrets offline via
spring-cloud-config-cli. - Store encrypted secrets in Git using
{cipher}...notation.
- Using HashiCorp Vault integration:
- Fetch secrets dynamically at runtime.
- Avoid storing any secrets in Git.
Transport Security
- Use HTTPS with properly signed certificates for Config Server and clients.
- Consider mutual TLS for two-way authentication in sensitive environments.
Actuator Endpoints Security
Restrict actuator endpoints with authentication & authorization to avoid unauthorized refreshes or info leaks.
Performance and Operational Best Practices
Scalability
- Run multiple Config Server instances behind a load balancer.
- Enable shallow cloning and local Git cache.
- Integrate Spring Cloud Bus with RabbitMQ/Kafka for efficient refresh event broadcasting.
Monitoring
- Monitor
/actuator/healthand/metricsof Config Server and clients. - Log and alert on Git repository access failures.
Backup & Rollback
- Git’s native versioning enables easy rollback of config changes.
- Maintain branch/tag strategies to isolate environment changes.
Limitations
- Spring Cloud Config does not provide an automatic polling mechanism for refreshing configuration. Clients must explicitly refresh or rely on event bus triggers.
- Managing encryption and secrets securely adds operational complexity.
- Branch and profile management can become complicated at scale.
- Not intended to replace full-featured secret management or service discovery tools.
Summary
Centralized, versioned configuration is essential for scaling modern Spring Boot microservices. Spring Cloud Config Server with Git backend offers a battle-tested, auditable, and dynamic approach to configuration management.
This guide took you through setting up the server, structuring configurations, building a client with runtime refresh, securing sensitive content, and handling typical production challenges.
Appropriately adopting Spring Cloud Config enhances collaboration, operational efficiency, and runtime flexibility — fundamental pillars for microservices success.
FAQ
Can I use Spring Cloud Config without Git?
Yes. Alternatives include local filesystem, Vault, or composite property sources. Git is preferred for versioning and audit but not mandatory.
How are active profiles resolved?
Clients specify active profiles on startup, which the Config Server uses to assemble configuration by merging files: global then profile-specific, app-specific then profile-specific.
Is communication between Config Server and clients secure by default?
No. You must configure TLS (HTTPS) explicitly, with optional mutual TLS. Encrypt secrets in transit and at rest.
How do I update the configuration without restarting the client?
Enable /actuator/refresh and annotate beans with @RefreshScope. You can manually invoke the refresh endpoint or automate with Spring Cloud Bus.
How does Spring Cloud Config handle encrypting secrets?
The server decrypts secrets using a configured keystore. Secrets are encrypted offline and stored in Git as cipher text. This prevents plaintext exposure.
Sources and further reading
- Spring Cloud Config Reference Documentation
- Spring Boot Actuator Documentation
- Spring Cloud Vault Documentation
- HashiCorp Vault Official
- Spring Initializr
