Migrating Lyft's Android Codebase to Kotlin
Article Summary
Oleksii Chyrkov from Lyft just closed the book on a 7-year migration journey. The final push to eliminate Java from their entire Android codebase revealed some brutal truths about automated tooling.
Lyft started adopting Kotlin in 2018, but by early 2025 still had 1,000+ Java files scattered across 20+ teams. The team built custom automation using Android Studio IDE Scripting to accelerate the final migration push across their Rider, Driver, and Urban Solutions apps.
Key Takeaways
- Custom migration script automated conversion and created git commits per module
- Auto-converter created verbose code with excessive nullable types like Observable<Optional<List<Ride?>?>?>?
- One legacy class had to stay in Java due to broken API contracts causing Kotlin crashes
- Added CI Lint check to permanently block new Java code from entering codebase
- Migration driven by Compose adoption, K2 compiler speed gains, and Coroutines framework
Lyft completed their 7-year Kotlin migration by building custom tooling that converted multiple modules daily, despite imperfect auto-conversion requiring extensive code review.
About This Article
Lyft's automated Java-to-Kotlin converter created messy code. It used too many nullable types like Observable<Optional<List<Ride?>?>?>?, was overly verbose, and missed Kotlin idioms such as map and filter operations. This affected over 150 Bazel modules.
Developer Oleksii Zaiats used Android Studio IDE Scripting to build a migration script. The script automated the conversion process, fixed common problems, created git commits for each module, and sent notifications to teams for review. This made it possible to migrate multiple modules every day.
Lyft reached 85% completion of the Kotlin migration by February 2025. The remaining work dropped from over 1,000 Java files to a smaller set. The team also added a permanent CI Lint check to stop new Java code from being added.