Mahib Hosain / Stripe / JVM modernization

Language upgrades
as a service

I led Stripe’s automated JDK upgrade platform, using live Bazel dependency graphs to determine eligibility, partition reviewable changes, and surface blockers.

Build graphs / eligibility / continuous upgrades
93%+
JDK 17 service adoption in under a week
160+
Upgrade PRs in the first three months
700+
Java services in Stripe’s codebase

The problem

Language upgrades become coordination problems when services share libraries and build dependencies. A service’s readiness depends on more than its own source code; the dependency graph determines which changes can move together and which are blocked.

The setting was Stripe’s 26M-line JVM codebase. That number describes the surrounding repository, not the amount of code migrated by this platform.

What I built

The platform made upgrades continuous work: derive eligibility from the live build graph, break the work into reviewable partitions, and expose the blockers that need engineering attention.

  1. Bazel graphCurrent dependency relationships
  2. EligibilityReady targets and blockers
  3. PartitionsReviewable changes
  4. Upgrade PRsChanges engineers can inspect

Build state informs the plan

Using live dependency relationships ties the upgrade plan to the codebase being changed. Blockers become explicit inputs to the work instead of remaining hidden in a migration checklist.

Reviewability is part of automation

Partitioning changes keeps the output inspectable by engineers. The platform’s job includes producing understandable changes and surfacing what it cannot yet upgrade.

Results & evidence

The rollout reached 93%+ JDK 17 service adoption in under a week, and generated more than 160 upgrade PRs in the first three months.

I coauthored Modern Java at Stripe: Language upgrades as a service with Cara Mecozzi. The article provides the fuller public engineering account. The internal platform implementation is not distributed here.

← PortfolioNext: Metals + Bazel →