- Published on
Migrating a Fleet of Spring Boot APIs with a Shared Parent POM
- Authors

- Name
- Motions Technologies
Migrating a Fleet of Spring Boot APIs with a Shared Parent POM
When you run more than a handful of Spring Boot microservices, version drift is not a theoretical risk — it is the default. One service sits on Boot 3.2, another on 3.5, Dockerfiles disagree on the JDK, and AWS SDK pins diverge. We recently took a food-delivery platform's API fleet (about twelve services) through a controlled upgrade to Spring Boot 4 and a modern JDK. The pattern that made it safe was a shared parent POM, the same idea banks use for governance.
The problem with per-service parents
Each API independently declared something like:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.x</version>
</parent>
plus duplicated java.version, compiler settings, and AWS SDK BOM imports. That is how fleets accumulate skew: every upgrade becomes twelve copy-paste edits and twelve chances to miss a Dockerfile or CI JDK pin.
Introduce a company parent POM
We published a thin parent artifact (hosted on GitHub Packages) that sits between Spring Boot and the APIs:
spring-boot-starter-parent
↑
company-api-parent (Boot + Java + AWS BOM)
↑
customer-api / order-api / payment-api / …
What the parent owns
- Boot and Java versions (one place to bump)
- AWS SDK for Java 2.x BOM in
dependencyManagement - Compiler / Surefire / Spring Boot plugin defaults
- Lombok annotation processing defaults
What the parent is not
- Not a monorepo reactor — APIs stay independent git repos
- Not forced shared libraries (those can come later)
- Children may add service-specific deps; they should not re-pin Boot/Java without a documented exception
Two-step adoption (do not jump everything at once)
Parent 1.x — adopt without upgrading Boot
First publish a parent that still targets the current Boot line (for us, Boot 3.5.x). Point every API at it. Run Maven + existing smoke tests. You have aligned governance before you change runtime behavior.
Parent 2.x — Boot 4 + JDK bump together
Spring Boot 4.1 supports a specific JDK window (through Java 26 at the time we ran this). We shipped Boot 4 and the new JDK in the same parent bump so compile, Docker base images, and CI setup-java stay on one supported matrix.
Per API when moving to parent 2.x:
- Bump
<parent><version> - Switch Dockerfile to the matching Temurin base image
- Align GitHub Actions JDK
- Run local Maven on that JDK before push
- Deploy behind smoke tests
DynamoDB before Boot 4 for heavy services
Several services still used the unmaintained spring-data-dynamodb stack. That combination is a poor foundation for Boot 4. We migrated those APIs to the AWS SDK v2 Enhanced Client (modules only, versions from the parent BOM) before their Boot 4 bump.
Safer wave order we used:
- Pilot a low-risk API on parent 2.x (Boot 4 + new JDK)
- Roll Boot 4 to APIs without Dynamo legacy
- Migrate Dynamo-heavy APIs to SDK v2 Enhanced Client
- Boot 4 the remaining services — payment last, with a longer soak
Smoke tests are the promotion gate
We treated pre/post-deploy HTTP smoke (Hurl suites per API) as the hard gate: if smoke fails, the service does not stay promoted. That discipline mattered more than any single migration checklist item. OpenRewrite helped with mechanical API changes; humans still owned dual-write edges, auth, and payment paths.
Lessons worth stealing
- Parent POM first, runtime jump second — alignment without behavior change reduces blast radius.
- Clear blocked dependencies early — unmaintained Spring Data Dynamo adapters will own your schedule if you ignore them.
- Pilot → wave → critical path last — payment and order flows get the longest soak.
- Document the inventory — keep a living table of Boot/Java/SDK versions per service; it pays for itself on the next fleet bump.
- Non-LTS JDKs are fine for short windows — plan the next LTS parent bump as normal ops cadence, not a surprise fire drill.
Closing
Fleet upgrades fail when every service invents its own Spring Boot line. A published parent POM turns "upgrade twelve repos" into "publish parent 2.0.0, then bump twelve parent versions." Pair that with dependency cleanup, a pilot service, and ruthless smoke gates, and Boot 4 becomes an engineering project instead of a weekend gamble.