Practical Guide to Managing Spring Boot Application Configuration with Spring Cloud Config

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

ApproachProsCons
Local filesSimple, no network dependenceDifficult to maintain at scale
Kubernetes ConfigNative to Kubernetes, secureKubernetes lock-in, less flexible
Consul/ZooKeeperHighly available, dynamicAdds operational complexity
Spring Cloud Config (Git)Versioned, familiar, auditableRequires 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 Server
  • Spring 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 profiles
  • application-{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.name must match config file names in Git
  • fail-fast causes 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

  1. Config Server exposes configuration stored in Git.
  2. Client fetches configuration matching its app name and active profile.
  3. Controller reads the injected custom.greeting property.
  4. Refresh endpoint allows live config changes without restarts.

Verification Steps

  1. Start Config Server:
  • Command: mvn spring-boot:run in server project
  • Verify port 8888 active
  1. Test Config Server REST:
curl http://localhost:8888/orderservice/prod

Expect JSON response with merged properties.

  1. Start Client Service:
  • mvn spring-boot:run in client project
  • Verify port 8080 active
  1. Test client property endpoint:
curl http://localhost:8080/greet

Response: greeting configured in Git.

  1. Update Config: Modify custom.greeting in Git repo and push changes.
  1. Refresh config dynamically:
curl -X POST http://localhost:8080/actuator/refresh
  1. Verify new value:
curl http://localhost:8080/greet

Response should reflect new greeting.


Production Failure Modes and Troubleshooting

IssueCauseResolution
Config Server fails to startIncorrect Git repo URL or permissionsVerify URL, credentials, and network access
Client startup failConfig Server unreachable; fail-fast enabledVerify server availability; disable fail-fast to debug
/actuator/refresh endpoint missingDependencies missing or endpoint not exposedAdd relevant dependencies and configure actuator exposure
Secrets show in logs or responsesNo encryption configuredImplement encryption or Vault integration
Configs not updating/actuator/refresh not calledAutomate 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:

  1. 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.
  1. 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/health and /metrics of 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


Related reading