Quarkus · Migration

Migrating from Spring Boot to Quarkus: a practical guide

Migrate a Spring Boot service to Quarkus step by step: annotation mapping, REST, config profiles, Panache, Spring compatibility extensions and common pitfalls.

By the JobSupport4U engineering team · Updated · 7 min read

Moving a service from Spring Boot to Quarkus is less dramatic than it sounds: the concepts — beans, configuration, REST endpoints, repositories, transactions — map almost one to one. This guide shows the mapping, side-by-side code, the Quarkus rules that trip Spring developers up, and a migration plan that keeps risk low.

Plan the migration first

  1. Start with one service, ideally a small, well-tested one — not the monolith.
  2. Inventory your Spring starters and find the matching Quarkus extensions (for example with quarkus extension list). Anything without an equivalent needs a decision early.
  3. Keep the contract identical: same REST paths, same Kafka topics and payloads, same database schema. Your existing integration tests become the safety net.
  4. Run in JVM mode first. Only consider a native build once everything works on the JVM.

The annotation mapping

Spring BootQuarkus
@Component, @Service@ApplicationScoped
@Autowired / constructor injection@Inject / constructor injection
@Value@ConfigProperty
@RestController, @RequestMapping@Path
@GetMapping, @PostMapping@GET, @POST
@PathVariable, @RequestParam@PathParam, @QueryParam
Spring Data JPA repositoriesHibernate ORM with Panache
@Scheduled@Scheduled (scheduler extension)
@SpringBootTest@QuarkusTest
application.yml with profilesapplication.properties with %dev. / %test. / %prod. prefixes

REST endpoints

Java · Spring Boot
@RestController
@RequestMapping("/orders")
public class OrderController {
  private final OrderService service;

  public OrderController(OrderService service) {
    this.service = service;
  }

  @GetMapping("/{id}")
  public Order get(@PathVariable String id) {
    return service.find(id);
  }
}
Java · Quarkus
@Path("/orders")
@Produces(MediaType.APPLICATION_JSON)
public class OrderResource {

  @Inject
  OrderService service;

  @GET
  @Path("/{id}")
  public Order get(@PathParam("id") String id) {
    return service.find(id);
  }
}

Configuration and profiles

Java · Quarkus
@ConfigProperty(name = "orders.page-size", defaultValue = "20")
int pageSize;
application.properties
quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://db:5432/orders
orders.page-size=50

In dev and test, Dev Services starts a PostgreSQL container for you automatically when no URL is configured — which is why the URL above only applies to the prod profile. If you prefer YAML, add the quarkus-config-yaml extension.

Data access with Panache

Panache keeps Hibernate ORM but removes boilerplate. In the active-record style, queries live on the entity:

Java · Quarkus
@Entity
public class Order extends PanacheEntity {
  public String customer;
  public String status;

  public static List<Order> findOpen() {
    return list("status", "OPEN");
  }
}

If you prefer repositories, implement PanacheRepository<Order> instead. Transactions use @Transactional from jakarta.transaction.

The Spring compatibility shortcut

Quarkus provides Spring compatibility extensions — for dependency injection, web, Data JPA and Boot-style properties — so many Spring annotations work unchanged. They are a useful bridge for migrating in steps, but they cover the common subset of Spring, not all of it. Plan to move to native Quarkus APIs over time.

Pitfalls Spring developers hit

  • Build-time configuration. Some Quarkus properties are fixed when the application is built and can’t be changed with an environment variable at runtime. The configuration reference marks them.
  • Runtime classpath scanning. Libraries that discover classes or use heavy reflection at runtime may need an extension or extra configuration — especially for native builds.
  • Security is different. Spring Security configuration doesn’t carry over; Quarkus uses its own security model and extensions such as OIDC. Re-test every protected endpoint.
  • Dev Services needs Docker (or another container runtime) on developer machines and CI.
  • Bean scopes: @ApplicationScoped beans are lazily created proxies, while @Singleton beans are not proxied — choose deliberately.

Migration checklist

  1. Pick one small, well-tested service.
  2. Map every Spring starter to a Quarkus extension.
  3. Port endpoints, config, persistence and scheduling using the mapping above.
  4. Re-implement security and re-test every protected endpoint.
  5. Run the existing integration and contract tests unchanged.
  6. Deploy in JVM mode; consider native once it’s stable.
Keep reading

More guides