Why Meta bet on Kotlin
Meta’s Android repository spans Facebook, Instagram, Messenger, Portal, and Quest. Moving that much code from Java to Kotlin is a major undertaking, but the payoff justifies the work. Kotlin scores higher in developer satisfaction than Java, and its design removes some recurring pain points:
- Nullability: Kotlin’s type system catches null-pointer issues at compile time rather than at runtime, reducing the crash-fixing cycle.
- Functional style without overhead: Kotlin’s inlined lambdas avoid the anonymous-object allocation that Java 8 lambdas incur on Android, especially on low-end devices.
- Concise code: Kotlin’s standard library and type inference replace repetitive loops with shorter, more readable statements.
- Type-safe builders: Kotlin enables DSLs that can replace Android XML definitions, though overuse can lead to overengineering.
There are real drawbacks. A mixed Java/Kotlin codebase creates interoperability quirks, and Kotlin’s tooling ecosystem is thinner than Java’s. The biggest concern at Meta was build time. Kotlin compilation is slower than Java’s, and with apps the size of Facebook’s, that directly affects developer productivity.
Two migration paths
Meta considered two broad approaches: allow new Kotlin code while leaving the Java codebase untouched, or convert nearly all in-house code to Kotlin.
The first option requires far less work, but it leaves most engineers editing Java most of the time, since most development touches existing code. It also introduces platform types at the Java/Kotlin boundary. Those types bypass Kotlin’s null checks and can produce runtime null-pointer crashes, undermining the reason for migrating in the first place. Java’s lack of nullable type parameters and its different overloading rules compound the interop issues.
Meta chose the second path: full conversion of in-house code. After clearing some early blockers, the team accelerated the effort. Today, each of the Facebook, Messenger, and Instagram Android apps contains over one million lines of Kotlin, and the total Android codebase now exceeds ten million lines.
Clearing the path
Initial attempts to use Kotlin in Meta’s existing apps surfaced tooling gaps. Redex, Meta’s bytecode optimizer, had to be updated to handle bytecode patterns that Java never produced. Internal libraries that transformed bytecode during compilation also needed changes to run under Kotlin. Many teams won’t face these issues — they’re specific to Meta’s in-house toolchain.
Other gaps were more universal. Syntax highlighting for Kotlin in code review and wikis required updates to Pygments. Meta also built its own deterministic formatter, Ktfmt, based on google-java-format, to ensure consistent Kotlin style.
Automating the conversion: Kotlinator
JetBrains’ Java-to-Kotlin converter (J2K) turns Java into Kotlin, but it’s a general tool. It has no knowledge of the frameworks in the code it converts, so its output needs substantial cleanup. One recurring example: JUnit test rules. J2K converts Java test rules into Kotlin fields with private visibility, which JUnit rejects at runtime because the @Rule annotation lands on a private field.
Fixing that case requires either adding @JvmField or switching the annotation use-site to @get:Rule. J2K can’t know every framework’s conventions, so such manual fixes multiply across the codebase.
Meta built Kotlinator, a three-stage pipeline to handle these systematic problems:
- Preparation: A Java package is pre-processed to work around known J2K bugs and adapt code for internal tools.
- Conversion: J2K runs via Android Studio in headless mode, controlled by a script.
- Post-processing: Automated refactors correct framework-specific issues like JUnit rules, then auto-fix linters and Android Studio suggestions run in headless mode.
Kotlinator targets active, simpler modules first. The team runs the script, checks whether the result compiles and passes continuous integration, and commits if it does. Unfamiliar or one-off problems are fixed manually in the same commit. Repeated issues trigger new automated refactors.
Java-side refactors rely on JavaASTParser for type resolution. For Kotlin, the team uses the Kotlin compiler APIs to parse code into a PSI AST, which handles structural changes without full type resolution. Meta is sharing a sample of these refactoring utilities on GitHub, including a template-matching tool that replaces Android’s TextUtils.isEmpty with Kotlin’s String.isNullOrEmpty. The Kotlin version is preferable not only because it’s part of the standard library, but also because its contract allows the compiler to smart-cast from nullable to non-nullable when the check passes.
What the migration taught us
Thanks to those tooling investments, Meta has already converted a substantial portion of its codebase. There are now more than 10 million lines of Kotlin, and most Android developers at the company write Kotlin as their primary language. That scale surfaced a handful of lessons worth recording.
Kotlin is shorter, but not dramatically
Heading in, the team expected Kotlin to trim file sizes considerably. In some cases it did — files were cut in half or more, particularly where Java code was full of null checks or where simple loops could be swapped for standard-library functions like first, single, or any, which accept lambdas.
Much of Meta's code, though, is essentially moving data between layers. UI definition classes, such as those written for Litho, wind up roughly the same length in either language. Across the entire migration, the average reduction was 11 percent in lines of code. That is lower than many numbers quoted online, which Meta suspects come from cherry-picked examples. The company is still satisfied, since the removed lines tend to be boilerplate that is less explicit than its shorter Kotlin replacement.
Runtime performance holds steady
Since Kotlin targets the same JVM bytecode as Java, no execution-speed regressions were expected. To verify, Meta ran several A/B tests comparing Java implementations with Kotlin ones that leaned on lambdas, nullability, and other Kotlin features. Performance matched, as anticipated.
APK size stays manageable
Because all releases are processed with Proguard and Redex, only a portion of the Kotlin standard library reaches a production APK. Size has not become an issue except in niche cases where a few extra kilobytes genuinely matter. There, developers found they could sidestep the Kotlin standard library and use existing Java equivalents — for instance, calling String.split instead of kotlin.text's CharSequence.split avoids pulling in additional classes and constants.
Build time is the real cost
Meta correctly predicted that build times would grow as Kotlin adoption spread. While the Kotlin compiler keeps improving on its own, the team also attacked the problem from its own side of the toolchain.
One avenue is source-only ABI support in the Buck build system. That feature, which already exists for Java, produces ABI jars for dependencies in the build graph without compiling them first. A Kotlin version is under development and is expected to flatten the build graph and meaningfully improve incremental builds.
Annotation processing was the other target. The existing KAPT route works by generating Java stubs for annotation processors, which is convenient for backwards compatibility but slow. KSP, the now-recommended approach, avoids the stub generation step. Meta added KSP support to Buck and is porting its processors with an adapter it wrote. That effort only pays off once no KAPT-based processors remain, so the migration work per processor is nontrivial. The interop library from the Room developers offers another path to reuse existing code, though it still requires per-processor changes.
Where Kotlin at Meta goes from here
The migration is still running and picking up pace. Any Android developer at Meta who wants to write Kotlin can now do so, backed by tooling that eases converting existing code to the language.
Kotlin still trails Java in some of the tools and optimizations Meta has gotten used to over the years. Closing those gaps is ongoing work, and as those tools and libraries mature, Meta intends to release them back to the open-source community.



