Spring API Compatibility Extensions

This section documents Quarkus 3.39.x (current) with 3.33.x LTS as the production recommendation, on the Java 17+ baseline, as published at the official Quarkus guides — which are the reference these pages are written and verified against.

Quarkus 4 raises the baseline to Java 21 (first release candidate planned for end of September 2026, see the Quarkus blog); readers upgrading past 3.39.x/3.33.x LTS should expect that change.

This content was generated with the assistance of AI and should be verified against those official guides before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Quarkus ships a family of Spring API compatibility extensions that let existing Spring-annotated code compile and run on Quarkus with little or no change to that code — but they implement the annotation APIs, translated onto Quarkus’s own build-time-resolved machinery, not Spring itself. There is no Spring ApplicationContext anywhere underneath, no Spring BeanFactory, and no guarantee that an arbitrary third-party Spring library will work simply because it is on the classpath. This page scopes each compatibility extension honestly — what it supports and what it deliberately does not — maps each Spring idiom to the Quarkus-native equivalent it sits in front of, and lays out a realistic migration path for an existing Spring Boot service.

What "compatibility" actually means here

Every extension below recognizes a specific, fixed set of Spring annotations at build time and translates each one into a call onto the corresponding Quarkus subsystem — CDI/ArC for dependency injection, Quarkus REST for web endpoints, the Quarkus Scheduler for @Scheduled, and so on. Recognizing an annotation is not the same as implementing the framework it came from: none of these extensions load Spring’s own core, instantiate a GenericApplicationContext, or support Spring’s runtime bean-post-processing SPI, ApplicationContextAware, Environment abstraction, or arbitrary @Conditional implementations. A Spring library that expects to participate in a real Spring context (registering its own BeanFactoryPostProcessor, reading ApplicationContext events, or relying on Spring AOP proxying beyond what the compatibility layer recognizes) will not work on Quarkus regardless of which compatibility extensions are added.

The extensions

Extension Supports

Does not support

spring-di

@Autowired, @Component/@Service/@Repository/@Configuration, @Bean, @Qualifier, @Primary, @Value for simple property injection — each translated onto the corresponding ArC/CDI construct (CDI and the Programming Model) at build time.

A real ApplicationContext; @ComponentScan configuration (Quarkus already discovers every bean-defining class at build time, so there is no scan path to configure); Spring’s BeanPostProcessor/ BeanFactoryPostProcessor SPI; programmatic bean lookup via ApplicationContext.getBean(…​).

spring-web

@RestController, @RequestMapping and its @GetMapping/@PostMapping/etc. shorthands, @PathVariable, @RequestParam, @RequestBody, @ResponseStatus — translated onto Quarkus REST endpoint metadata at build time.

Spring MVC’s DispatcherServlet and its full request-handling pipeline; WebMvcConfigurer and other Spring-specific interceptor/filter registration; @ControllerAdvice-based global exception handling beyond what Quarkus REST’s own exception mapping already recognizes; Spring WebFlux’s reactive controller style (Mono/Flux return types) — Quarkus’s own reactive style is Uni/Multi (Reactive Programming and Mutiny).

spring-data-jpa

Spring Data-style repository interfaces (extends JpaRepository<T, ID>/CrudRepository<T, ID>) with derived query methods and @Query-annotated JPQL, backed by Hibernate ORM underneath.

The full Spring Data infrastructure — no QueryDSL integration, a narrower derived-query-method keyword vocabulary than upstream Spring Data JPA, and no custom-repository-fragment auto-wiring beyond the basic interface-inheritance pattern.

spring-data-rest

Exposing a spring-data-jpa repository as a REST resource with minimal configuration, similar in spirit to Spring Data REST.

Spring Data REST’s full HATEOAS feature set (HAL/ALPS representations, projection/excerpt configuration, event-based hooks) — treat this as a convenience subset, not a like-for-like port.

spring-tx

org.springframework.transaction.annotation.Transactional, recognized and mapped onto Quarkus’s own Jakarta-Transactions-based transaction management (jakarta.transaction.Transactional, covered on Datasources and Transactions) so existing @Transactional-annotated Spring service methods keep working unmodified.

Spring’s own PlatformTransactionManager SPI or programmatic TransactionTemplate usage; only a subset of Spring’s propagation/isolation options is honored, mapped onto what the underlying Jakarta transaction manager actually supports.

spring-security

A subset of Spring Security’s method-security annotations (@Secured, a limited-SpEL subset of @PreAuthorize) layered on top of Quarkus Security.

Spring Security’s filter-chain configuration (SecurityFilterChain beans), its full SpEL expression grammar in @PreAuthorize/@PostAuthorize, and its OAuth2 client/resource-server libraries — Quarkus’s own OIDC and authentication mechanisms (Security Authentication Mechanisms, Security: JWT, OIDC and Keycloak) are the native path for anything beyond simple role checks.

spring-cache

@Cacheable, @CacheEvict, @CachePut, mapped onto Quarkus’s own cache extension underneath.

Spring’s CacheManager SPI or a Spring-specific cache provider (Redis, Caffeine configured the Spring way) —  the actual caching engine is Quarkus’s, only the annotation surface is Spring’s.

spring-scheduled

@Scheduled with cron, fixedRate, and fixedDelay, mapped onto the Quarkus Scheduler extension.

Spring’s TaskScheduler bean customization or @EnableScheduling-adjacent configuration beyond simply having the extension present.

spring-boot-properties

@ConfigurationProperties-style property binding, translated onto Quarkus’s own SmallRye-Config-based configuration (Configuration) — reading the same application.properties/.yaml files Quarkus itself uses.

Spring Boot’s relaxed-binding edge cases in full, its Environment abstraction, or Spring Boot Actuator —  Quarkus’s config binding for new code should use @ConfigMapping ( Configuration) directly rather than this compatibility annotation.

spring-cloud-config-client

Fetching configuration from an existing Spring Cloud Config Server as one more Quarkus config source, useful specifically for adopting Quarkus incrementally alongside a Spring Cloud estate that already centralizes configuration this way.

Any other part of Spring Cloud (service discovery, circuit breakers, gateway) — Quarkus’s own equivalents for those concerns (Fault Tolerance and Resilience, Kubernetes and OpenShift) are unrelated to this extension.

spring-test

A small set of Spring Test annotations recognized on top of @QuarkusTest, letting an existing Spring-annotated test class keep compiling with minimal edits.

MockMvc, Spring’s TestContext framework, or @SpringBootTest’s full context-caching/slicing behavior —  Quarkus’s own testing model (@QuarkusTest`, @InjectMock, @QuarkusTestResource) is the native path for a test written from scratch.

Mapping table: Spring idiom to Quarkus-native equivalent

Spring idiom Quarkus-native equivalent Notes

@Autowired field/constructor

@Inject (ArC/CDI)

Direct, mechanical rename in the common case; see CDI and the Programming Model.

@Component/@Service/@Repository

@ApplicationScoped (or another CDI scope)

Also mechanical, though the default scope differs conceptually — CDI has no single "just a bean" stereotype the way Spring’s component-scanning does; picking the right scope is a small, deliberate step.

@RestController + @GetMapping/etc.

@Path + @GET/@POST/etc. (Quarkus REST)

Mechanical for a plain CRUD-style controller; a controller with custom `HandlerInterceptor`s or content-negotiation configuration needs a rewrite against Quarkus REST’s own extension points.

@Transactional (Spring)

@Transactional (jakarta.transaction)

Same annotation name, different package and underlying transaction manager — an import change more than a logic change for the common propagation cases.

@Scheduled

io.quarkus.scheduler.Scheduled

Cron/fixedRate/fixedDelay semantics carry over directly; see Scheduling and Mail.

@Cacheable/@CacheEvict

io.quarkus.cache.CacheResult/CacheInvalidate

Same shape, different annotation names and package — see Caching.

@Value("${…​}")

@ConfigProperty or a @ConfigMapping interface

A @ConfigMapping interface is the better long-term target even when @Value-equivalent injection would technically work, per Configuration.

@PreAuthorize("hasRole('ADMIN')")

@RolesAllowed("ADMIN") (Jakarta) or Quarkus Security’s own annotations

A simple role check maps directly; a @PreAuthorize SpEL expression referencing method arguments or beans has no general Quarkus-native equivalent and needs to become explicit code.

ApplicationContext / BeanFactory lookups

CDI.current().select(…​) (rare) or, preferably, ordinary injection

Programmatic context lookups are a code smell in CDI the same way they are increasingly discouraged in modern Spring — a genuine migration is the moment to remove them, not translate them.

Spring AOP @Around advice

A CDI interceptor (@AroundInvoke)

Conceptually equivalent, covered on CDI and the Programming Model, but the binding mechanism (interceptor-binding annotation vs. pointcut expression) is different enough to need a genuine rewrite, not a search-and-replace.

Diagram mapping common Spring annotations on the left — @Autowired

A realistic migration path

What transfers close to annotation-for-annotation, once the corresponding compatibility extension is added: simple @Component/@Service/@Autowired wiring, a CRUD-shaped @RestController, @Transactional service methods with ordinary propagation, @Scheduled jobs, and @Cacheable/@CacheEvict caching. A service built mostly from these idioms, with no deep Spring-specific configuration, can often be recompiled against the compatibility extensions and run with only import and small annotation-attribute changes.

What must be rewritten, not translated: Spring Security’s filter-chain configuration and anything beyond simple role checks in @PreAuthorize; Spring AOP pointcut expressions beyond what a CDI interceptor binding naturally expresses; any code that calls ApplicationContext/BeanFactory directly; Spring Boot Actuator (Quarkus’s own observability stack, Observability, is the replacement); Spring Cloud beyond the config-client extension above; and Spring WebFlux’s Mono/Flux-based reactive controllers, which have no compatibility-extension equivalent at all — a reactive Quarkus REST endpoint is written against Uni/Multi from the start (Reactive Programming and Mutiny).

When a rewrite is cheaper than a port: a service whose value is concentrated in Spring-specific infrastructure — heavy custom Spring AOP, a deep Spring Cloud microservices setup (service discovery, a Spring Cloud Gateway front end, Spring Cloud Stream bindings), or WebFlux-based reactive pipelines — typically costs more effort to keep working through the compatibility layer than to rewrite directly against Quarkus’s native equivalents, because the compatibility extensions were never meant to replicate that infrastructure. A service whose logic is mostly plain CRUD, straightforward REST endpoints, and ordinary transactional/scheduled/cached methods is the profile where the compatibility extensions genuinely shorten a migration; anything past that profile is worth prototyping natively before committing to a port.