Improving the Management of Java Microservices
I have joined a number of projects over the years that use Java microservices, and every team seems to do things a little differently. Each environment came with its own methodologies, pain points, and upgrade challenges. Over time, I have learned what works well and what creates unnecessary friction. A clean, centralized strategy for managing dependencies has consistently made upgrades and vulnerability resolutions far easier.
In this post, I will walk through the most common options and then go deeper into the hybrid Gradle Catalog and Maven BOM approach I have been using recently. These strategies can support both Gradle and Maven, and they scale well as your number of microservices grows.
What Are My Options?
The right approach depends on the number of microservices, your build toolchain, and whether you use a Gradle multi-module setup. The most common patterns I have seen include:
Independent Handling
The standard pattern. Each microservice manages its own versions and dependencies. This works fine for small projects but quickly becomes difficult as the microservice count grows.
Multi-module Gradle Monorepo
A strong option. A top-level Gradle project manages shared versions, and child modules inherit them automatically.
Maven BOM
A proven solution that works for both Gradle and Maven. A BOM file centralizes dependency versions so services can reference consistent versions without repetition.
Gradle Catalog
A newer Gradle-specific feature that allows you to manage versions, libraries, and plugins in a single place. Similar to a Maven BOM, but within the Gradle ecosystem.
Gradle Catalog with Maven BOM (Hybrid)
My preferred solution. Use a BOM for shared common dependencies and a Catalog for items you do not want managed at the BOM level. This gives you a single source of truth for versions and plugins while supporting flexibility across teams and services.
What Is a Gradle Catalog?
Gradle Version Catalogs became stable in Gradle 8.x after being experimental in 7.x. They allow you to define and manage:
- Dependency versions
- Library coordinates
- Plugin versions
All inside a single version catalog file. This is common in Android but works well in any Gradle project. Once defined, your microservices can reference versions directly from the catalog. You can learn more in the official Gradle documentation.
What Is a Maven BOM?
A Maven BOM is a special POM that centralizes dependency versions. Any project that imports the BOM can reference dependencies without repeating version numbers. It is widely used, works with both Maven and Gradle, and simplifies upgrades. More details are available in the Maven documentation.
Why Use Both?
Combining a Gradle Catalog with a Maven BOM gives you the best of both worlds:
- Manage all versions in a single place through the catalog
- Keep BOM contents limited to shared common dependencies
- Manage plugins in the catalog
- Ensure every catalog version is tied to a specific BOM version
- Avoid breaking changes by controlling upgrade paths
In short, you get structure without losing flexibility.
How Does This All Work Together?
The first step is to build your catalog. To do that, review your existing microservices and determine what should be lifted into a shared BOM. I created a standalone Gradle project that houses both the catalog and the BOM and handles publishing.
The Catalog
Your catalog lives in the same project as the BOM. Inside gradle/libs.versions.toml, you define:
- Version numbers
- Libraries
- Plugins
This file becomes the single source of truth that your microservices can reference. When published, Gradle automatically picks it up if the consuming service uses Gradle 8.x or higher.
Example catalog file:
Making the BOM
The BOM looks simple at first glance. It is a dependency block inside a Gradle build file using the java-platform plugin. The key is that you leverage the catalog while building the BOM so your previous definitions flow into your shared dependency structure.
Example BOM build file:
Publishing the BOM and Catalog
To publish both, you use the maven-publish plugin and configure the publication to your chosen Maven repository.
Example publishing configuration:
Working Sample
I put together a working sample on GitHub that demonstrates this entire flow.
It includes:
- A sample module that generates the BOM and Catalog
- Local publishing to a Maven repository
- A sample service that consumes both
You can explore it here: Java Microservices with BOM and Catalog Example
Final Thoughts
The sample includes versioning patterns, overrides, and practical usage examples. It also shows how the catalog and BOM work together in a standard Spring Boot application.
If you are looking to simplify the management of your Java microservices, unify your versioning, and reduce friction during upgrades, this approach creates a clean structure that scales. Once implemented, you get consistent dependency management, clearer notes through the because clause, and a publishing workflow that fits neatly into any enterprise environment.
This process has made my own projects much easier to maintain, and I hope it helps you streamline yours as well.
About the Author
Adam Utsch
Senior Principal Consultant
Adam is a seasoned software professional with deep experience in development, deployment, and application support. With a strong engineering foundation, they specialize in building scalable solutions and mentoring others in the technologies that drive real impact. Adam is passionate about continuous improvement, collaboration, and staying ahead of the tech curve.