Enterprise Java Supply Chains: Spring, Quarkus, Tanzu, and RHBQ Compared
A hands-on look at CVE patching and support lifecycles and why your choice of binaries shapes the reliability and predictability of production systems.
When developers compare frameworks, the debate usually focuses on features, performance, or startup time. Those matter, but they’re not the whole story. There’s a more fundamental question that cuts deeper than benchmarks:
Who takes responsibility for the code you run?
It’s not just a matter of convenience. The provenance of your dependencies determines how quickly you can patch vulnerabilities, how reproducible your builds are, and how much hidden risk you pass downstream to your customers.
Choosing a framework is never just a technical decision. It’s a question of trust, responsibility, and the kind of codebase you want to leave behind. It also includes practical considerations like supported configurations and lifecycle guarantees.
Both Spring Boot and Quarkus have vibrant open-source communities. But most enterprises eventually face a choice: stay with community builds, or adopt an enterprise distribution such as Tanzu Spring (Broadcom/VMware) or the Red Hat Build of Quarkus (RHBQ). In this article, we’ll compare the different approaches and see how they stack up.
Disclaimer: This overview is based on the linked, public sources and my own experience. I’ve aimed for balance, but if you spot inaccuracies on either side, please let me know — in the comments, on social, or via email — and I’ll happily correct them.
This article:
Explains the difference between the Red Hat build of Quarkus and community Quarkus.
Shows how that model compares to Spring Boot’s approach.
Walks through a hands-on example using the same codebase for both Spring Boot and RHBQ to illustrate the practical differences.
Gives you a high level overview about the Enterprise support offerings and how they compare.
Community Builds: Fast, Open, but Short-Lived
Spring Boot and Framework releases are published directly to Maven Central. Dependencies like Jackson, Tomcat, and Hibernate are pulled unchanged from their upstream projects.
The community support window is short, typically one year per line. Once that window closes, CVEs are no longer patched and you need to upgrade. While the Spring Boot BOM keeps versions aligned, every artifact remains an upstream binary. The Spring release planning is mapped out on a calendar.
Quarkus follows a similar model. The release roadmap is developed openly on GitHub, and you can see when a major, minor, or patch release is targeted.
The Quarkus community moves quickly, often shipping new minor releases every few months. That innovation comes at the cost of no formal long-term support guarantee. If you rely solely on the community, you’re expected to keep up with the cadence.
Key highlights:
Spring OSS: ~1 year support per line, Maven Central binaries.
Quarkus OSS: open planning, fast cadence, no LTS guarantee.
Both: great for experimentation and innovation, not ideal for regulated enterprises.
Tanzu Spring (Broadcom/VMware)
Tanzu Spring productizes the entire Spring portfolio with over 50 projects (Framework, Boot, Data, Cloud, Security, Batch, Integration, etc.), plus Apache Tomcat (via Tanzu tc Server) and OpenJDK (via BellSoft Liberica).
Support lifecycle
Every minor release: 24 months of support.
Final minor of each major: 5 additional years.
Example: Spring Boot 2.7, released May 2022, supported until end of 2026 Lifecycle Docs.
Patch process
When a CVE hits a dependency like Jackson or Tomcat, Broadcom updates the BOM and ships a new Spring Boot or Framework patch release. You adopt that patch, which may also bring unrelated upgrades.
Tooling
Spring Application Advisor automates upgrades using OpenRewrite recipes, generating pull requests.
Tanzu also provides compliance-focused extensions via the Spring Boot Governance Starter (FIPS, PCI-DSS).
Linux and Windows, across VMs, containers, and Kubernetes.
Supported as long as the underlying OS vendor still provides security updates. (my interpretation!)
Probably best integrated with VMware’s own Tanzu/VM offerings
Highlights:
Up to 7 years of support.
Enterprise binaries from Broadcom’s private repo (
repo.spring.vmware.com
). (Guides)Patch delivery = BOM-level patch releases.
Broad cross-platform support.
Red Hat Build of Quarkus (RHBQ)
RHBQ takes a supply chain–centric approach: every artifact is rebuilt from source by Red Hat, including all transitives, and tagged with a .redhat-xxxxx
suffix. This guarantees provenance and allows surgical CVE fixes. The supported components and their support levels can be accessed on the customer portal.
Support lifecycle
Each major supported for ~3 years: ~2.5 years Full Support + 6 months Maintenance (RHBQ Lifecycle).
Example: Quarkus 3, GA Oct 2023 → supported until Oct 2026.
Patch process
When a CVE hits, Red Hat backports and rebuilds just the affected artifact. Customers get a new .redhat
jar in the same stream. No unrelated dependency churn.
Tooling
Quarkus CLI for project upgrades (blog)
Quarkus VSCode extension (marketplace)
Migration Toolkit for Applications (MTA)
Certified on RHEL and OpenShift.
Supported on Windows Server (x86_64) with Adoptium JDK.
Comes with UBI base images and Mandrel native image builds optimized for RHEL.
Highlights:
~3 years of support per major.
All artifacts rebuilt,
.redhat
suffix ensures traceability.Surgical CVE patching without BOM churn.
Supported on Linux (Adoptium), RHEL, OpenShift, and Windows.
Why This Matters: Dependency Provenance
In the community model (Quarkus or Spring Boot), you consume artifacts published by dozens of upstream maintainers. The framework BOM aligns versions, but ultimately you are running whatever those projects shipped to Maven Central.
That works until a CVE or compliance audit arrives. Then you discover that no single party takes responsibility for the whole chain. You wait, you juggle versions, you hope nothing else breaks. The risk shifts downstream: To you.
In the RHBQ model:
Red Hat owns the full dependency graph for your runtime.
Every artifact is rebuilt from source, scanned, tested, and versioned together.
When a CVE is discovered, Red Hat doesn’t shrug and wait. It applies the fix and reissues the affected jar, leaving everything else untouched.
The difference is simple but profound: one model outsources responsibility to dozens of maintainers; the other accepts accountability on your behalf.
Hands-On: One Codebase, Two Runtimes
Let’s build a tiny REST API once with Spring Boot, and once with RHBQ. Using the same source code thanks to Quarkus’s Spring compatibility layer. And yes, I would have loved to do this with the Tanzu Spring dependencies but I do not have access to the customer binaries.
This isn’t about “Hello World tricks.” It’s about proving that developers can take what they know today and run it under a model that respects their time and their responsibility to deliver secure, stable systems.
Prerequisites
JDK 17+
Maven 3.8+
Git (optional)
Create a new Maven Project
mvn archetype:generate -DgroupId=com.example.app -DartifactId=community-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
cd community-app
If you want to, you can grab this little example from my Github repository and play around with it.
Shared Source Code
src/main/java/com/example/app/GreetingService.java
package com.example.app;
import org.springframework.stereotype.Service;
@Service
public class GreetingService {
public String greet(String name) {
return "Hello, " + (name == null || name.isBlank() ? "world" : name) + "!";
}
}
src/main/java/com/example/app/GreetingController.java
package com.example.app;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class GreetingController {
private final GreetingService svc;
public GreetingController(GreetingService svc) { this.svc = svc; }
@GetMapping("/greet")
public String greet(@RequestParam(required = false) String name) {
return svc.greet(name);
}
}
This uses standard Spring annotations. When you run it on Quarkus, they are maped internally with quarkus-spring-web
and quarkus-spring-di
.
Spring Boot Build
Spring Boot pom.xml
, main class, run with mvn spring-boot:run
.
Inspect dependencies: plain upstream artifacts from Maven Central.
pom.xml
for Spring Boot
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-app</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
Add a Spring Boot main class:
src/main/java/com/example/app/Application.java
package com.example.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Run:
mvn spring-boot:run
Open: http://localhost:8080/api/greet?name=Spring
Inspect dependencies:
mvn dependency:tree
Output excerpt:
org.springframework.boot:spring-boot-starter-web:3.2.5
├─ org.springframework:spring-webmvc:6.1.6
├─ org.apache.tomcat.embed:tomcat-embed-core:10.1.20
├─ com.fasterxml.jackson.core:jackson-databind:2.15.4
├─ ch.qos.logback:logback-classic:1.4.14
└─ org.apache.logging.log4j:log4j-to-slf4j:2.21.1
These are upstream artifacts from Maven Central and they have no vendor suffix.
Red Hat Build of Quarkus Build
pom.xml
for RHBQ. Make sure to rename the Application.java to Application.java_ so it won’t be compiled.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>quarkus-rhbq-app</artifactId>
<version>1.0.0</version>
<properties>
<compiler-plugin.version>3.11.0</compiler-plugin.version>
<quarkus.platform.group-id>com.redhat.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.version>3.20.2.redhat-00002</quarkus.platform.version>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
<skipITs>true</skipITs>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>red-hat-enterprise-maven-repository</id>
<url>https://maven.repository.redhat.com/ga/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>red-hat-enterprise-maven-repository</id>
<url>https://maven.repository.redhat.com/ga/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-di</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
Run in dev mode:
quarkus dev
Open: http://localhost:8080/api/greet?name=Quarkus
Inspect dependencies:
mvn dependency:tree
Output excerpt:
io.quarkus:quarkus-spring-web:3.20.2.redhat-00003
├─ io.quarkus:quarkus-arc:3.20.2.redhat-00003
├─ io.vertx:vertx-core:4.5.16.redhat-00009
├─ io.netty:netty-codec-http:4.1.121.Final-redhat-00002
├─ com.fasterxml.jackson.core:jackson-databind:2.18.2.redhat-00004
└─ org.jboss.logging:jboss-logging:3.6.1.Final-redhat-00001
Almost every artifact carries a .redhat-xxxxx
suffix, showing it was rebuilt in Red Hat’s supply chain. And I personally only know one exception to this rule :) Comment on the article if you have found it yourself.
Comparing the Two Trees
diff
the dependency trees:
mvn dependency:tree > spring-tree.txt
mvn dependency:tree > rhbq-tree.txt
diff -u spring-tree.txt rhbq-tree.txt | less
Provenance
Spring Boot: each dependency is the original upstream artifact.
RHBQ: every dependency is rebuilt, tested, and tagged as part of a coherent stream.
Security patching model
Spring Boot: CVE fixes require upstream → Spring BOM → app upgrade.
RHBQ: Red Hat can patch and republish
.redhat
versions directly within the same stream.
Dependency graph stability
Spring Boot: updating can potentially drag in unrelated upgrades.
RHBQ: targeted updates (only affected
.redhat
artifacts change), reducing regression risk.
The Spring Boot tree represents the community ecosystem. Flexible but dependent on upstream cadence. The RHBQ tree represents an enterprise-controlled ecosystem. Every jar comes from a single vendor pipeline, ensuring traceability, backporting, and predictable behavior in production.
When a CVE Hits
Scenario: CVE in com.fasterxml.jackson.core.
Spring Boot path: wait for the Jackson project to fix → wait for Spring Boot BOM update → upgrade Spring Boot.
RHBQ path: Red Hat patches & rebuilds → releases updated
.redhat
artifact within same stream → no unrelated churn.
Every unpatched CVE is not just a technical inconvenience, it’s a liability. It risks customer data, compliance standing, and reputation.
One model leaves you waiting while risk accumulates. The other takes direct responsibility to close the gap.
Why Developers Should Care
Both ecosystems provide a viable enterprise path, but they optimize for different goals:
Spring OSS is excellent for rapid development and innovation, but short support windows demand frequent upgrades.
Quarkus OSS gives early access to cutting-edge features, with open release planning and transparency, but no lifecycle guarantees.
Tanzu Spring offers stability and breadth. If your enterprise is standardized on Spring, Tanzu is the natural choice. Expect long lifetimes (up to 7 years), but patches come as BOM-level updates. You will need processes to handle dependency churn.
RHBQ offers control and provenance. If you run on RHEL or OpenShift, RHBQ aligns perfectly: every jar is vendor-rebuilt, patches are surgical, and builds are fully certified. The trade-off is a slightly shorter lifetime.
Recommendations:
Choose Tanzu Spring if: Your organization is already deeply locked into Spring, believes guaranteed long-term support outweighs agility, and accepts the responsibility that comes with BOM-level upgrades.
Choose RHBQ if: You need surgical CVE patching, supply-chain provenance, and the confidence of vendor certification, including deep integration with Red Hat platforms.
Stay on community builds if: you can afford rapid upgrades, want early access, or are in non-critical environments.