SP

spring-boot-config-refactor

Refactors legacy Spring properties to structured, immutable YAML configuration. Improves maintainability and type safety.

Install

mkdir -p .claude/skills/spring-boot-config-refactor && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/13395" && unzip -o skill.zip -d .claude/skills/spring-boot-config-refactor && rm skill.zip

Installs to .claude/skills/spring-boot-config-refactor

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Refactor a Spring Boot application's configuration from legacy application.properties and scattered @Value usage to structured YAML and immutable @ConfigurationProperties records. Use this when migrating messy configuration, standardizing property naming, introducing app-prefixed custom properties, or separating sensible defaults from local development overrides.
365 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Analyze existing Spring Boot configuration
  • Restructure configuration to YAML
  • Migrate `@Value` to `@ConfigurationProperties` records
  • Introduce `app` prefixed custom properties
  • Separate local development overrides

How it works

The skill analyzes existing Spring Boot configuration, restructures it to YAML, and migrates `@Value` annotations to type-safe, immutable `@ConfigurationProperties` records.

Inputs & outputs

You give it
Spring Boot application with `application.properties` and `@Value` annotations
You get back
Spring Boot application with YAML configuration and `@ConfigurationProperties` records

When to use spring-boot-config-refactor

  • Convert properties to YAML
  • Introduce type-safe config records
  • Standardize application config prefixes
  • Separate environment-specific overrides

About this skill

Spring Boot configuration refactor skill

Use this skill when the task is to analyze, restructure, and migrate application configuration in a Spring Boot codebase.

This skill is specifically optimized for repositories where:

  • application.properties has grown organically over time and is hard to understand.
  • Local development uses a dev profile and an additional config location such as devops/dev/config/.
  • Test and production deployments are configured externally through Kubernetes ConfigMap/Secret/sealed secrets rather than profile-specific packaged files.
  • Many settings are injected via @Value annotations.
  • The goal is to move to type-safe, immutable, record-based configuration using @ConfigurationProperties.

Desired target state

Follow these rules unless the user explicitly instructs otherwise:

  1. Use YAML instead of .properties for Spring configuration.
  2. Put application-specific properties under the app prefix.
  3. Keep standard Spring Boot / framework / library properties under their normal prefixes (for example spring.*, management.*, server.*, logging.*).
  4. Keep the same conceptual split between:
    • application.yml for minimal defaults and shared base configuration.
    • application-dev.yml for local development overrides.
    • application-test.yml for Spring Boot test scenarios when relevant.
  5. Migrate from scattered @Value usage to @ConfigurationProperties with immutable Java records.
  6. Inject configuration records as Spring beans via constructor injection.
  7. Add validation so invalid configuration fails fast during startup.
  8. Preserve the existing deployment model where production/test environment overrides come from external configuration, Kubernetes config maps, and secrets.
  9. Do not introduce environment-specific packaged config for production unless the user explicitly asks for it.

Key implementation principles

Configuration layout

  • src/main/resources/application.yml
    • Keep it minimal.
    • Include sensible defaults only.
    • Do not hardcode environment-specific secrets or infrastructure endpoints.
    • Use Spring Boot's native property keys directly for framework properties (spring.activemq.*, spring.data.redis.*, etc.) rather than creating intermediate "bridge" property layers (e.g. activemq.broker.urlspring.activemq.broker-url). Set localhost/empty defaults inline and let K8s ConfigMaps override with real values.
  • src/main/resources/application-dev.yml
    • Use for local dev defaults and local overrides only if that matches the repo's current practice.
    • If the project already loads external files from devops/dev/config/ using spring.config.additional-location, preserve that approach unless the user asks to change it.
  • src/test/resources/application-test.yml
    • Use when test-specific configuration is needed.

Property modeling

  • Group custom application properties into one or more records under a dedicated package such as:
    • ...config
    • ...config.properties
    • or the package already used by the project for application config
  • Prefer a small number of well-structured top-level property records over many tiny fragmented ones.
  • Use nested records to mirror the YAML hierarchy.
  • Keep names domain-oriented and self-explanatory.
  • Multi-module projects: each Gradle/Maven module that needs config should have its own @ConfigurationProperties record bound to its relevant subtree. For example, a main app module gets AppProperties (prefix = "app"), while an integration-foo module gets FooProperties (prefix = "app.integration.foo"). This keeps each module self-contained and avoids forcing a dependency on the root config record.

Example pattern:

package com.example.app.config.properties;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@Validated
@ConfigurationProperties(prefix = "app")
public record AppProperties(
    @Valid Feature feature,
    @Valid Integration integration
) {
    public record Feature(
        boolean enabled,
        @Min(1) int batchSize
    ) {}

    public record Integration(
        @NotBlank String baseUrl,
        @NotNull Timeout timeout
    ) {
        public record Timeout(
            @Min(1) int connectSeconds,
            @Min(1) int readSeconds
        ) {}
    }
}

Spring Boot wiring

  • Prefer @ConfigurationPropertiesScan on the main application class if it is not already in use.
  • Alternatively use @EnableConfigurationProperties(...) only when there is a strong repository-specific reason (for example, test @Configuration classes that don't trigger @SpringBootTest auto-scanning — see the test pitfalls section).
  • Use constructor injection exclusively.
  • Access values using record accessors, for example appProperties.integration().baseUrl().
  • Dependency: @Validated on @ConfigurationProperties records requires spring-boot-starter-validation. Check if it is already present before adding it.

Validation

  • Use @Validated on the configuration record.
  • Use Jakarta Bean Validation annotations such as:
    • @NotNull
    • @NotBlank
    • @Min
    • @Max
    • @Positive
    • @Valid for nested records
  • Ensure configuration errors fail fast at application startup.
  • @Valid on nested records does NOT enforce non-null: @Valid Security security means validation runs on the nested record's contents only if the record is non-null. If the property subtree is absent, the component is null and @Valid null passes silently. At runtime, accessing security().hashSalt() then throws NullPointerException. Use @NotNull @Valid if the component must always be present, or accept that the component may be null and guard access accordingly.

Handling existing @Value usage

Auditing @Value annotations

  • Search the codebase for all @Value annotations — but distinguish Lombok @Value from Spring @Value. Lombok @Value is a class-level annotation (generates getters, equals, hashCode). Spring @Value is org.springframework.beans.factory.annotation.Value and is used on fields/parameters for property injection. Filter for the Spring import, not just @Value text matches.
  • Also search for @Scheduled, @JmsListener, @KafkaListener, and other annotations that use ${...} placeholders in their attributes (e.g. @Scheduled(cron = "${my.cron}"), @JmsListener(destination = "${my.queue}")). These are property references that will break when legacy keys are removed, but they do not show up in a @Value search.

Classifying properties

Classify each occurrence:

  1. custom application property → migrate under app.*
  2. framework/library property → usually leave as framework config and inject a richer Spring abstraction where possible
  3. literal default with occasional override need → model as a typed property with a sensible default in YAML, or keep optional via constructor defaulting only if clearly justified

Migrating classes

  • Replace field injection and @Value injection with constructor-injected configuration beans.
  • When using Lombok @RequiredArgsConstructor for constructor injection, be aware that @RequiredArgsConstructor does not propagate @Qualifier annotations. If a bean needs both a @ConfigurationProperties record and a @Qualifier-annotated bean (e.g. a named RestClient), keep @Autowired @Qualifier on the qualified field (non-final) and make only the config properties field final for constructor injection.
  • Remove dead properties after migration.

Bridge properties and infrastructure config

Legacy configurations often have "bridge" properties — custom intermediate property keys that are referenced by Spring Boot's native property placeholders. For example:

# Bridge pattern (avoid in target state):
redis:
  host: 127.0.0.1
  port: 6379
spring:
  data:
    redis:
      host: "${redis.host}"
      port: "${redis.port}"

During migration:

  • Identify all bridge properties during the audit phase. Common examples: db.*spring.datasource.*, activemq.broker.*spring.activemq.*, redis.*spring.data.redis.*.
  • Replace bridges with direct values in application.yml. Set localhost/empty defaults for spring.activemq.*, spring.data.redis.*, etc. directly, and let K8s ConfigMaps override using the standard Spring property names (or their env var equivalents via Spring Boot's relaxed binding, e.g. SPRING_ACTIVEMQ_BROKER_URL).
  • If a bridge cannot be removed immediately (e.g. db.* properties are used to compose spring.datasource.url via ${db.server}:${db.port}/${db.name}), keep it temporarily and document it as a follow-up cleanup.

Property naming rules

  • Application-specific keys must move under app.
  • Avoid flat names when the domain has hierarchy.
  • Prefer this:
    • app.integration.certificate-service.base-url
    • app.jobs.cleanup.batch-size
  • Avoid this:
    • certificateServiceUrl
    • cleanupBatch

Secrets and external config

  • Never hardcode secrets in repository defaults.
  • Assume sensitive values should come from environment variables, sealed secrets, or external config in the devops repository.
  • Prefer env var placeholders for secrets where possible, for example app.security.hash-salt: "${HASH_SALT:}".
  • Preserve compatibility with spring.config.additional-location if the project already relies on it.

Required workflow — phased migration

When using this skill, follow this phased workflow. Each phase should result in a passing test suite and a separate commit. The user can review, test, and roll back each phase independently.

Phase 1: Audit the current state

Inspect at leas


Content truncated.

When not to use it

  • When the goal is to convert standard Spring Boot properties to `app.*`
  • When the project requires mutable configuration POJOs instead of records
  • When the user explicitly wants environment-specific packaged config for production

Limitations

  • The skill is optimized for repositories with specific configuration practices.
  • It does not introduce environment-specific packaged config for production unless explicitly asked.
  • It avoids renaming properties consumed by shared libraries without coordination.

How it compares

This skill automates the refactoring of Spring Boot configuration to a structured, type-safe YAML and record-based approach, standardizing property naming and separating concerns, unlike manual, ad-hoc configuration changes.

Compared to similar skills

spring-boot-config-refactor side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
spring-boot-config-refactor (this skill)04moNo flagsAdvanced
refactor03moNo flagsAdvanced
java-pro344moNo flagsAdvanced
backend-microservice-development23moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

refactor

jgreen021

This standard governs the modernization of legacy code and the surgical decomposition of high-complexity monolithic structures.

00

java-pro

sickn33

Master Java 21+ with modern features like virtual threads, pattern matching, and Spring Boot 3.x. Expert in the latest Java ecosystem including GraalVM, Project Loom, and cloud-native patterns. Use PROACTIVELY for Java development, microservices architecture, or performance optimization.

3492

backend-microservice-development

TencentBlueKing

后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。

213

microservice-infrastructure

TencentBlueKing

微服务基础设施指南,涵盖条件配置、事件驱动架构、服务间通信、国际化与日志等微服务架构的核心基础设施。当用户实现服务间调用、配置多环境、实现异步通信、处理国际化或规范日志输出时使用。

411

common-technical-practices

TencentBlueKing

通用技术实践指南,涵盖 AOP 切面、分布式锁、重试机制、参数校验、性能监控、定时任务、审计日志等后端开发中的常见技术实践。当用户需要实现横切关注点、处理并发控制、配置重试策略、添加性能监控或实现审计功能时使用。

26

jakarta-namespace

benchflow-ai

Migrate Java EE javax.* imports to Jakarta EE jakarta.* namespace. Use when upgrading to Spring Boot 3.x, migrating javax.persistence, javax.validation, javax.servlet imports, or fixing compilation errors after Jakarta EE transition. Covers package mappings, batch sed commands, and verification steps.

25

Search skills

Search the agent skills registry