Spring Boot to Quarkus Migration
Modular, gate-driven migration of Spring Boot applications to Quarkus.
Critical Rules
- Never delete code you cannot migrate. If you cannot fully migrate a piece of code, leave the original in place with a
// TODO: Migration required — <reason> comment explaining what needs to change and why. This applies to:
- Methods, classes, or annotations you don't know how to convert
- Spring-specific patterns without a clear Quarkus equivalent
- Configuration or wiring code whose purpose is unclear
If you must remove code (e.g., a Spring-only base class), document what was removed and why in a
// REMOVED: comment at the same location.
- Don't break the build. Run the compile command after each phase (
./mvnw clean compile -DskipTests for Maven, ./gradlew clean compileJava -x test for Gradle). Never move to the next phase with a broken build.
- Document every decision. When choosing between migration approaches, explain the trade-off to the user.
- No silent changes. Every file modification must be intentional and traceable. If a check fails after a phase, diagnose and fix — don't skip the check or delete the failing code.
Reference Files
Load the relevant reference file when working on a module:
| Reference |
Use during |
| references/dependency-map.md |
Build module: dependency and plugin mapping |
| references/annotation-map.md |
Code module: annotation, DI, REST, Data, Security migration |
| references/config-map.md |
Build module: configuration property migration |
Step 1: Analyze & Choose Strategy
Scan the application to understand what needs to migrate:
- Build system: Read the build file (
pom.xml for Maven, build.gradle or build.gradle.kts for Gradle) — Spring Boot version, starters, plugins
- Java code: Search for Spring annotations (DI, REST, Data, Security, Scheduling)
- Configuration: Read
application.properties/application.yml, check for profiles
- UI / View layer: Check for Thymeleaf/JSP templates, static resources, Model+View patterns
- Tests: Check for
@SpringBootTest, @WebMvcTest, @DataJpaTest
Present a summary table with area, findings, and complexity. Then choose the migration strategy:
Strategy selection
Resolve the strategy using the following priority (first match wins):
Skill argument — if the skill was invoked with a strategy argument (spring-compat or full-quarkus), use it directly.
Project config file — check for .quarkus-migration.yml in the project root. If it exists and contains a strategy field, use that value. Example file:
# .quarkus-migration.yml
strategy: spring-compat # or full-quarkus
Ask the user — if neither of the above provided a strategy, ask the user to choose:
- Spring compatibility (
spring-compat, recommended): Use quarkus-spring-web, quarkus-spring-data-jpa, etc. Minimal code changes.
- Full Quarkus (
full-quarkus): Replace all Spring annotations with JAX-RS/CDI. More work, full Quarkus experience.
Stop here and wait for the user's response before continuing. Do not ask about git workflow or anything else in the same message.
If the strategy was resolved from an argument or config file, log: Strategy: <value> (source: <argument|config file>) and continue without asking.
Step 2: Git branch (optional)
After the user has chosen a strategy, check if the target project is a git repository. If it is, propose the git workflow:
Migration workflow: Each migration run can be isolated in its own branch (migration/run-01, migration/run-02, ...) created from main. The branch will contain a single commit with all changes plus a migration report. A draft PR against main will be created for review — it is never merged, it serves as a permanent diff and discussion record. Would you like to use this workflow?
- User accepts → follow modules/git/git.md — Pre-migration section. Propose the branch name and wait for confirmation before creating it.
- User declines → skip git management entirely, proceed with migration in the current branch.
- Not a git repo → inform the user, skip git management, proceed normally.
Step 3: Execute Modules
Instructions
- Execute the instructions of the modules according to the following Decision Gate Table
- Always log which Module and Gate check is evaluated and the status using the format:
Gate result: and
Decision Gate Table
- For each module, evaluate whether it applies to this project. A module executes only when its gate status is: PASS.
- Inspect the project to determine the gate result — do not rely on blind grep commands; use your understanding of the codebase.
| Module |
Gate Check |
Gate Result |
| jdk |
JDK 21+ required |
ALWAYS -- stop migration if < 21 |
| build |
Spring Boot parent/starters/spring-boot-maven-plugin in pom.xml, or Spring Boot/io.spring.dependency-management plugins in build.gradle(.kts) |
PASS if Spring Boot build markers found; SKIP otherwise |
| code |
Spring annotations in Java sources (@Component, @Service, @Controller, @Repository, @Entity, @Autowired, etc.) |
PASS if Spring annotations found; SKIP otherwise |
| frontend |
Thymeleaf/JSP templates in templates/ or static resources in static/ |
PASS if view layer found; SKIP otherwise |
| testing |
Spring test annotations in test sources (@SpringBootTest, @WebMvcTest, @MockBean) |
PASS if Spring tests found; SKIP otherwise |
| cleanup |
Leftover Spring artifacts after all other modules |
ALWAYS — runs after all other modules |
Execution Protocol
FOR module IN [build, code, frontend, testing, cleanup]:
1. EVALUATE — inspect the project for the gate condition
2. DECIDE
IF gate == ALWAYS → proceed to step 3
IF gate == PASS → proceed to step 3
IF gate == SKIP → log "Module {name}: SKIPPED — {reason}", mark checkbox, continue
3. LOAD — read the module file and relevant reference files
4. EXECUTE — follow the module instructions, adapting to the chosen strategy
5. COMPILE — run the project's compile command (`./mvnw clean compile -DskipTests` for Maven, `./gradlew clean compileJava -x test` for Gradle)
Fails → diagnose and fix before proceeding
6. LOG — mark checkbox as done
Running Individual Modules
To run a single module outside the full migration flow, read all the files in the module folder directly:
- "Read
modules/build/build.md and execute it"
- "Run only the frontend module"
- "Re-run the cleanup module"
The module will use the current project state and the chosen strategy (if already decided). If no strategy has been chosen, the module will ask.
Step 4: Verify the Migration
Run each check in order. A check fails = stop and fix before continuing.
| # |
Check |
Command (Maven / Gradle) |
Pass criteria |
| 1 |
Builds |
./mvnw clean package -DskipTests / ./gradlew clean build -x test |
Exit code 0, no compilation errors |
| 2 |
No Spring deps |
Search build file for org.springframework |
Zero Spring deps (except Spring compat extensions if using that strategy) |
| 3 |
Has Quarkus |
Search build file for io.quarkus |
Quarkus BOM and at least one extension present |
| 4 |
Tests pass |
./mvnw test / ./gradlew test |
All tests pass using @QuarkusTest |
| 5 |
Starts up |
./mvnw quarkus:dev / ./gradlew quarkusDev |
App starts, curl http://localhost:8080/q/health returns UP |
| 6 |
No leftover templates |
Search for Thymeleaf/JSP references |
None remaining (unless intentionally kept) |
Step 5: Migration Review (Self-Reflection)
Answer each question honestly:
- What migrated cleanly? Patterns that mapped 1:1.
- What required manual judgment? Non-obvious decisions made.
- What was left as TODO? Every
// TODO: Migration required comment and why.
- Was any code removed? What, where, justification. Flag runtime risks.
- What checks failed initially? Failures from Step 4 and how you fixed them.
- What's missing from the skill references? Mappings you had to figure out.
Migration Report
Present the review as a structured report:
## Migration Report: [app-name]
### Summary
- Strategy: [Full Migration / Spring Compatibility]
- Agent: [AI agent name - e.g claude, pi, opencode, gemini, etc]
- Model: [model name — e.g. claude-sonnet-4-6, check system context]
- Modules completed: [X/4]
- Checks passed: [X/6]
- Token usage: [input tokens / output tokens — check session stats]
- Estimated cost: [~$X.XX — token counts × per-model pricing from anthropic.com/pricing]
### Changes by Module
| Module | Files changed | Key changes |
|--------|--------------|-------------|
| build | pom.xml or build.gradle(.kts), application.properties | ... |
| code | ... | ... |
| frontend | ... | ... |
| testing | ... | ... |
### Validation Results
| Check | Result | Notes |
|-------|--------|-------|
| Builds | PASS/FAIL | |
| No Spring deps | PASS/FAIL | |
| Has Quarkus | PASS/FAIL | |
| Tests pass | PASS/FAIL | |
| Starts up | PASS/FAIL | |
| No leftover templates | PASS/FAIL | |
### Unmigrated Code (TODOs)
| File | Line | What | Why not migrated |
|------|------|------|-----------------|
### Removed Code
| File | What was removed | Justification |
|------|-----------------|---------------|
### Skill Improvement Suggestions
- [Any missing mappings, unclear instructions, or edge cases discovered]
Step 6: Commit and PR (only if git workflow was accepted)
Follow modules/git/git.md — Post-migration section. Ask the user for confirmation before committing, and again before pushing / creating the draft PR. Do not proceed with either action without explicit user approval.
1---2name: migrate-spring-to-quarkus3description: Migrates Spring Boot applications to Quarkus using a modular, gate-driven approach. Supports Spring compatibility extensions and full Quarkus migration paths. Use when the user wants to migrate, convert, or port a Spring Boot app to Quarkus, mentions "spring to quarkus", "quarkus migration", "replace spring", or asks about migrating "pom.xml", "build.gradle", "Spring MVC", "Spring Data JPA", "Thymeleaf", "@SpringBootApplication".4license: Apache-2.05---67# Spring Boot to Quarkus Migration89Modular, gate-driven migration of Spring Boot applications to Quarkus.1011## Critical Rules1213- **Never delete code you cannot migrate.** If you cannot fully migrate a piece of code, leave the original in place with a `// TODO: Migration required — <reason>` comment explaining what needs to change and why. This applies to:14 - Methods, classes, or annotations you don't know how to convert15 - Spring-specific patterns without a clear Quarkus equivalent16 - Configuration or wiring code whose purpose is unclear17 If you must remove code (e.g., a Spring-only base class), document what was removed and why in a `// REMOVED:` comment at the same location.18- **Don't break the build.** Run the compile command after each phase (`./mvnw clean compile -DskipTests` for Maven, `./gradlew clean compileJava -x test` for Gradle). Never move to the next phase with a broken build.19- **Document every decision.** When choosing between migration approaches, explain the trade-off to the user.20- **No silent changes.** Every file modification must be intentional and traceable. If a check fails after a phase, diagnose and fix — don't skip the check or delete the failing code.2122## Reference Files2324Load the relevant reference file when working on a module:2526| Reference | Use during |27|---|---|28| [references/dependency-map.md](references/dependency-map.md) | Build module: dependency and plugin mapping |29| [references/annotation-map.md](references/annotation-map.md) | Code module: annotation, DI, REST, Data, Security migration |30| [references/config-map.md](references/config-map.md) | Build module: configuration property migration |313233## Step 1: Analyze & Choose Strategy3435Scan the application to understand what needs to migrate:3637- **Build system**: Read the build file (`pom.xml` for Maven, `build.gradle` or `build.gradle.kts` for Gradle) — Spring Boot version, starters, plugins38- **Java code**: Search for Spring annotations (DI, REST, Data, Security, Scheduling)39- **Configuration**: Read `application.properties`/`application.yml`, check for profiles40- **UI / View layer**: Check for Thymeleaf/JSP templates, static resources, Model+View patterns41- **Tests**: Check for `@SpringBootTest`, `@WebMvcTest`, `@DataJpaTest`4243Present a summary table with area, findings, and complexity. Then choose the migration strategy:4445### Strategy selection4647Resolve the strategy using the following priority (first match wins):48491. **Skill argument** — if the skill was invoked with a `strategy` argument (`spring-compat` or `full-quarkus`), use it directly.502. **Project config file** — check for `.quarkus-migration.yml` in the project root. If it exists and contains a `strategy` field, use that value. Example file:51 ```yaml52 # .quarkus-migration.yml53 strategy: spring-compat # or full-quarkus54 ```553. **Ask the user** — if neither of the above provided a strategy, ask the user to choose:56 - **Spring compatibility** (`spring-compat`, recommended): Use `quarkus-spring-web`, `quarkus-spring-data-jpa`, etc. Minimal code changes.57 - **Full Quarkus** (`full-quarkus`): Replace all Spring annotations with JAX-RS/CDI. More work, full Quarkus experience.5859 **Stop here and wait for the user's response before continuing.** Do not ask about git workflow or anything else in the same message.6061If the strategy was resolved from an argument or config file, log: `Strategy: <value> (source: <argument|config file>)` and continue without asking.6263## Step 2: Git branch (optional)6465After the user has chosen a strategy, check if the target project is a git repository. If it is, propose the git workflow:6667> **Migration workflow:** Each migration run can be isolated in its own branch (`migration/run-01`, `migration/run-02`, ...) created from `main`. The branch will contain a single commit with all changes plus a migration report. A draft PR against `main` will be created for review — it is never merged, it serves as a permanent diff and discussion record. **Would you like to use this workflow?**6869- **User accepts** → follow [modules/git/git.md](modules/git/git.md) — **Pre-migration** section. Propose the branch name and wait for confirmation before creating it.70- **User declines** → skip git management entirely, proceed with migration in the current branch.71- **Not a git repo** → inform the user, skip git management, proceed normally.7273## Step 3: Execute Modules7475## Instructions7677- Execute the instructions of the modules according to the following Decision Gate Table78- Always log which Module and Gate check is evaluated and the status using the format:79 Gate result: <STATUS> and <CONDITION_EVALUATED>8081### Decision Gate Table 8283- For each module, evaluate whether it applies to this project. A module executes only when its gate status is: **PASS**.84- Inspect the project to determine the gate result — do not rely on blind grep commands; use your understanding of the codebase.8586| Module | Gate Check | Gate Result |87|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|88| [jdk](modules/jdk/jdk.md) | JDK 21+ required | **ALWAYS** -- stop migration if < 21 |89| [build](modules/build/build.md) | Spring Boot parent/starters/`spring-boot-maven-plugin` in `pom.xml`, or Spring Boot/`io.spring.dependency-management` plugins in `build.gradle(.kts)` | **PASS** if Spring Boot build markers found; **SKIP** otherwise |90| [code](modules/code/code.md) | Spring annotations in Java sources (`@Component`, `@Service`, `@Controller`, `@Repository`, `@Entity`, `@Autowired`, etc.) | **PASS** if Spring annotations found; **SKIP** otherwise |91| [frontend](modules/frontend/frontend.md) | Thymeleaf/JSP templates in `templates/` or static resources in `static/` | **PASS** if view layer found; **SKIP** otherwise |92| [testing](modules/testing/testing.md) | Spring test annotations in test sources (`@SpringBootTest`, `@WebMvcTest`, `@MockBean`) | **PASS** if Spring tests found; **SKIP** otherwise |93| [cleanup](modules/cleanup/cleanup.md) | Leftover Spring artifacts after all other modules | **ALWAYS** — runs after all other modules |9495### Execution Protocol9697```98FOR module IN [build, code, frontend, testing, cleanup]:99100 1. EVALUATE — inspect the project for the gate condition101 2. DECIDE102 IF gate == ALWAYS → proceed to step 3103 IF gate == PASS → proceed to step 3104 IF gate == SKIP → log "Module {name}: SKIPPED — {reason}", mark checkbox, continue105 3. LOAD — read the module file and relevant reference files106 4. EXECUTE — follow the module instructions, adapting to the chosen strategy107 5. COMPILE — run the project's compile command (`./mvnw clean compile -DskipTests` for Maven, `./gradlew clean compileJava -x test` for Gradle)108 Fails → diagnose and fix before proceeding109 6. LOG — mark checkbox as done110```111112### Running Individual Modules113114To run a single module outside the full migration flow, read all the files in the module folder directly:115116- "Read `modules/build/build.md` and execute it"117- "Run only the frontend module"118- "Re-run the cleanup module"119120The module will use the current project state and the chosen strategy (if already decided). If no strategy has been chosen, the module will ask.121122## Step 4: Verify the Migration123124Run each check in order. A check fails = stop and fix before continuing.125126| # | Check | Command (Maven / Gradle) | Pass criteria |127|---|-------|---------|---------------|128| 1 | **Builds** | `./mvnw clean package -DskipTests` / `./gradlew clean build -x test` | Exit code 0, no compilation errors |129| 2 | **No Spring deps** | Search build file for `org.springframework` | Zero Spring deps (except Spring compat extensions if using that strategy) |130| 3 | **Has Quarkus** | Search build file for `io.quarkus` | Quarkus BOM and at least one extension present |131| 4 | **Tests pass** | `./mvnw test` / `./gradlew test` | All tests pass using `@QuarkusTest` |132| 5 | **Starts up** | `./mvnw quarkus:dev` / `./gradlew quarkusDev` | App starts, `curl http://localhost:8080/q/health` returns UP |133| 6 | **No leftover templates** | Search for Thymeleaf/JSP references | None remaining (unless intentionally kept) |134135## Step 5: Migration Review (Self-Reflection)136137Answer each question honestly:1381391. **What migrated cleanly?** Patterns that mapped 1:1.1402. **What required manual judgment?** Non-obvious decisions made.1413. **What was left as TODO?** Every `// TODO: Migration required` comment and why.1424. **Was any code removed?** What, where, justification. Flag runtime risks.1435. **What checks failed initially?** Failures from Step 4 and how you fixed them.1446. **What's missing from the skill references?** Mappings you had to figure out.145146### Migration Report147148Present the review as a structured report:149150```151## Migration Report: [app-name]152153### Summary154- Strategy: [Full Migration / Spring Compatibility]155- Agent: [AI agent name - e.g claude, pi, opencode, gemini, etc]156- Model: [model name — e.g. claude-sonnet-4-6, check system context]157- Modules completed: [X/4]158- Checks passed: [X/6]159- Token usage: [input tokens / output tokens — check session stats]160- Estimated cost: [~$X.XX — token counts × per-model pricing from anthropic.com/pricing]161162### Changes by Module163| Module | Files changed | Key changes |164|--------|--------------|-------------|165| build | pom.xml or build.gradle(.kts), application.properties | ... |166| code | ... | ... |167| frontend | ... | ... |168| testing | ... | ... |169170### Validation Results171| Check | Result | Notes |172|-------|--------|-------|173| Builds | PASS/FAIL | |174| No Spring deps | PASS/FAIL | |175| Has Quarkus | PASS/FAIL | |176| Tests pass | PASS/FAIL | |177| Starts up | PASS/FAIL | |178| No leftover templates | PASS/FAIL | |179180### Unmigrated Code (TODOs)181| File | Line | What | Why not migrated |182|------|------|------|-----------------|183184### Removed Code185| File | What was removed | Justification |186|------|-----------------|---------------|187188### Skill Improvement Suggestions189- [Any missing mappings, unclear instructions, or edge cases discovered]190```191192## Step 6: Commit and PR (only if git workflow was accepted)193194Follow [modules/git/git.md](modules/git/git.md) — **Post-migration** section. Ask the user for confirmation before committing, and again before pushing / creating the draft PR. Do not proceed with either action without explicit user approval.