Migrate Spring Boot applications to Quarkus. Supports full migration (idiomatic JAX-RS/CDI/Panache) and compatibility migration (using quarkus-spring-* extensions). Use when the user wants to convert a Spring Boot project to Quarkus.
Migrate a Spring Boot application to Quarkus. This skill guides a systematic, file-by-file migration.
Ask the user which strategy to use (or decide based on project complexity):
quarkus-spring-web, quarkus-spring-di, quarkus-spring-data-jpa). Faster migration, less rewriting, but not idiomatic Quarkus.If not specified, default to full migration.
Before changing anything, understand the project:
pom.xml (or build.gradle) — list all Spring dependenciesapplication.properties / application.yml — note all config keyssrc/main/java/ — identify:
@RestController, @Controller)@Service, @Component)@Repository, Spring Data interfaces)@Configuration, @Bean)WebSecurityConfigurerAdapter, SecurityFilterChain)@Scheduled)@EventListener)@SpringBootApplication)src/main/resources/templates/ — identify template engine (Thymeleaf, Freemarker)src/test/java/ — identify test patternsProduce a brief migration plan listing each file and what needs to change.
Replace the Spring Boot build with Quarkus.
For Maven (pom.xml):
Remove spring-boot-starter-parent and replace with Quarkus BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>3.21.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Replace spring-boot-maven-plugin with:
<plugin>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>3.21.3</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
<goal>native-image-agent</goal>
</goals>
</execution>
</executions>
</plugin>
Add the Quarkus compiler plugin configuration:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemPropertyVariables>
</configuration>
</plugin>
Map all Spring dependencies to Quarkus equivalents using the dependency map.
Remove all org.springframework* dependencies (unless using compatibility strategy).
Convert application.properties / application.yml using the config map.
Key patterns:
spring.datasource.url → quarkus.datasource.jdbc.urlspring.jpa.hibernate.ddl-auto → quarkus.hibernate-orm.database.generationserver.port → quarkus.http.portapplication-dev.properties) → Quarkus profiles (%dev. prefix or application-dev.properties)If the project uses application.yml and you want to keep YAML, add quarkus-config-yaml dependency. Otherwise convert to application.properties.
Work through files systematically using the annotation map.
@SpringBootApplication main class (Quarkus doesn't need one)CommandLineRunner or ApplicationRunner logic, move to a bean with void onStart(@Observes StartupEvent ev)Full migration:
@RestController → @Path("/...") @ApplicationScoped@GetMapping("/path") → @GET @Path("/path")@PostMapping → @POST, etc.@PathVariable → @PathParam (or @RestPath)@RequestParam → @QueryParam (or @RestQuery)@RequestBody → just the parameter (no annotation needed in Quarkus REST)ResponseEntity<T> → return T directly, or RestResponse<T> for status control@ExceptionHandler → @ServerExceptionMapper or ExceptionMapper<T>Compatibility migration:
quarkus-spring-web dependencyFull migration:
@Service / @Component → @ApplicationScoped@Autowired → @Inject@Value("${prop}") → @ConfigProperty(name = "prop")@Configuration + @Bean → @ApplicationScoped class with @Produces methodsCompatibility migration:
quarkus-spring-di dependencyFull migration (Panache Active Record):
// Before: Spring Data
public interface PetRepository extends JpaRepository<Pet, Long> {
List<Pet> findByName(String name);
}
// After: Panache Active Record
@Entity
public class Pet extends PanacheEntity {
public String name;
public static List<Pet> findByName(String name) {
return find("name", name).list();
}
}
Full migration (Panache Repository):
@ApplicationScoped
public class PetRepository implements PanacheRepository<Pet> {
public List<Pet> findByName(String name) {
return find("name", name).list();
}
}
Compatibility migration:
quarkus-spring-data-jpaFull migration (recommended):
src/main/resources/templates/th:text="${name}" → {name}th:each="item : ${items}" → {#for item in items}...{/for}th:if="${condition}" → {#if condition}...{/if}th:href="@{/path}" → href="/path"th:replace="fragments/header" → {#include header /}TemplateInstance from Qute type-safe templatesKeeping Thymeleaf:
quarkus-thymeleaf community extension (if available) or serve as raw templatesSecurityFilterChain / WebSecurityConfigurerAdapter with application.properties config@PreAuthorize("hasRole('X')") → @RolesAllowed("X")quarkus-elytron-security-properties-filequarkus-oidcquarkus-security with form auth config@Scheduled(cron = "...") → @io.quarkus.scheduler.Scheduled(cron = "...")@EnableScheduling@SpringBootTest → @QuarkusTest@MockBean → @InjectMock (from quarkus-junit5-mockito)TestRestTemplate → RestAssured: given().when().get("/path").then().statusCode(200)@ActiveProfiles("test") → @TestProfile(...) or %test. config prefix@WebMvcTest → @QuarkusTest with RestAssured@DataJpaTest → @QuarkusTest (test with real DB or H2 via %test. datasource config)src/main/java/*Application.java (the main class) if not already donespring-boot-devtools referencesMETA-INF/spring.factories or META-INF/spring/ auto-configuration filesorg.springframework imports remain (unless compatibility strategy)./mvnw compile to check for compilation errors, fix iteratively./mvnw test to check tests pass, fix iteratively./mvnw quarkus:dev to verify the app starts and basic endpoints work./mvnw compile./mvnw test./mvnw quarkus:dev@Transactional: Quarkus uses jakarta.transaction.Transactional, not Spring'ssrc/main/resources/META-INF/resources/ (not static/)quarkus.http.test-port)quarkus.index-dependency