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.zipInstalls 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.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
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.propertieshas grown organically over time and is hard to understand.- Local development uses a
devprofile and an additional config location such asdevops/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
@Valueannotations. - 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:
- Use YAML instead of
.propertiesfor Spring configuration. - Put application-specific properties under the
appprefix. - Keep standard Spring Boot / framework / library properties under their normal prefixes (for example
spring.*,management.*,server.*,logging.*). - Keep the same conceptual split between:
application.ymlfor minimal defaults and shared base configuration.application-dev.ymlfor local development overrides.application-test.ymlfor Spring Boot test scenarios when relevant.
- Migrate from scattered
@Valueusage to@ConfigurationPropertieswith immutable Java records. - Inject configuration records as Spring beans via constructor injection.
- Add validation so invalid configuration fails fast during startup.
- Preserve the existing deployment model where production/test environment overrides come from external configuration, Kubernetes config maps, and secrets.
- 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.url→spring.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/usingspring.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
@ConfigurationPropertiesrecord bound to its relevant subtree. For example, a mainappmodule getsAppProperties(prefix = "app"), while anintegration-foomodule getsFooProperties(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
@ConfigurationPropertiesScanon 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@Configurationclasses that don't trigger@SpringBootTestauto-scanning — see the test pitfalls section). - Use constructor injection exclusively.
- Access values using record accessors, for example
appProperties.integration().baseUrl(). - Dependency:
@Validatedon@ConfigurationPropertiesrecords requiresspring-boot-starter-validation. Check if it is already present before adding it.
Validation
- Use
@Validatedon the configuration record. - Use Jakarta Bean Validation annotations such as:
@NotNull@NotBlank@Min@Max@Positive@Validfor nested records
- Ensure configuration errors fail fast at application startup.
@Validon nested records does NOT enforce non-null:@Valid Security securitymeans validation runs on the nested record's contents only if the record is non-null. If the property subtree is absent, the component isnulland@Valid nullpasses silently. At runtime, accessingsecurity().hashSalt()then throwsNullPointerException. Use@NotNull @Validif 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
@Valueannotations — but distinguish Lombok@Valuefrom Spring@Value. Lombok@Valueis a class-level annotation (generates getters, equals, hashCode). Spring@Valueisorg.springframework.beans.factory.annotation.Valueand is used on fields/parameters for property injection. Filter for the Spring import, not just@Valuetext 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@Valuesearch.
Classifying properties
Classify each occurrence:
- custom application property → migrate under
app.* - framework/library property → usually leave as framework config and inject a richer Spring abstraction where possible
- 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
@Valueinjection with constructor-injected configuration beans. - When using Lombok
@RequiredArgsConstructorfor constructor injection, be aware that@RequiredArgsConstructordoes not propagate@Qualifierannotations. If a bean needs both a@ConfigurationPropertiesrecord and a@Qualifier-annotated bean (e.g. a namedRestClient), keep@Autowired @Qualifieron the qualified field (non-final) and make only the config properties fieldfinalfor 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 forspring.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 composespring.datasource.urlvia${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-urlapp.jobs.cleanup.batch-size
- Avoid this:
certificateServiceUrlcleanupBatch
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-locationif 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.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| spring-boot-config-refactor (this skill) | 0 | 4mo | No flags | Advanced |
| refactor | 0 | 3mo | No flags | Advanced |
| java-pro | 34 | 4mo | No flags | Advanced |
| backend-microservice-development | 2 | 3mo | No flags | Intermediate |
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.
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.
backend-microservice-development
TencentBlueKing
后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。
microservice-infrastructure
TencentBlueKing
微服务基础设施指南,涵盖条件配置、事件驱动架构、服务间通信、国际化与日志等微服务架构的核心基础设施。当用户实现服务间调用、配置多环境、实现异步通信、处理国际化或规范日志输出时使用。
common-technical-practices
TencentBlueKing
通用技术实践指南,涵盖 AOP 切面、分布式锁、重试机制、参数校验、性能监控、定时任务、审计日志等后端开发中的常见技术实践。当用户需要实现横切关注点、处理并发控制、配置重试策略、添加性能监控或实现审计功能时使用。
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.