# Thrifty traded Thrift boilerplate for immutable Kotlin, then was deprecated

> Thrifty is Microsoft's Apache Thrift implementation for Android, generated around public final fields instead of getters and setters, which cut the method count of the generated code from 20,000 to 5,000 in the Outlook for Android codebase. The repository is marked deprecated, with an active fork maintained elsewhere.

**microsoft/thrifty** — Thrift for Android that saves you methods

- Repository: https://github.com/microsoft/thrifty
- Website: https://github.com/benjamin-bader/thrifty
- Stars: 544 · Forks: 101
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/microsoft-thrifty

## Deprecation first, because it changes the answer

The README opens with a note that this repository is deprecated, with a link to issue 540, and states that an active fork can be found at github.com/benjamin-bader/thrifty. The homepage recorded in the project metadata points at the same fork. That changes what a reasonable adoption decision looks like, because the interesting engineering in this repository is now read-only history rather than a dependency you should be adding to a new build. What follows is still worth understanding, since the fork inherits the same design and the same trade-offs, and since plenty of Android services still speak Thrift. The licence is Apache-2.0, the primary language is Kotlin, and the last push to this repository was on 2026-09-23, with the most recent releases being 3.1.0 from 2022-12-13, 3.1.0-RC02 from 2022-06-09 and 3.0.0 from 2021-08-08. The repository is not archived, so the code is still readable and buildable.

## The method count problem on Android

Thrift is a widely-used cross-language service-definition stack, with an interface definition language from which types and RPC implementations are generated. The problem Thrifty targets is what the canonical compiler produces for Android. As the README puts it, the canonical implementation generates very verbose and method-heavy Java code, in a manner that is not very Proguard-friendly. The specific cost is that generated Thrift classes are full of accessors, and on Android every accessor is a method, and every method is a thing R8 and Proguard have to reason about, and every method in the dependency graph is a candidate for the multidex limit and for build time. Thrifty does away with getters and setters, and with is-setters and set-is-setters, in favour of public final fields. It keeps some core abstractions such as Transport and Protocol, but saves on methods by dispensing with Factories, omitting server implementations by default, and only generating code for the protocols you actually need. The measured outcome in the README is concrete: Thrifty was born in the Outlook for Android codebase, where before Thrifty the generated thrift classes consumed 20,000 methods, and after Thrifty the thrift method count dropped to 5,000.

## Wire compatibility with Apache Thrift, and the deliberate differences

Thrifty structs and clients are 100% compatible with Apache Thrift services, which is the point: you can drop it into an existing system without changing the wire format. The differences are listed in the README and they are all consequences of the immutability decision. Thrifty structs are immutable, and they are always valid once built, so consuming code does not have to constantly check whether required data is set. Fields that are neither required nor optional, in other words default fields, are treated as optional, and a struct with an unset default field may still be serialized. TupleProtocol is unsupported at present. And server-specific features are only supported for Kotlin code generation and are currently considered experimental. That last point is the one to plan around. If your service is a server rather than only a client, the server side of the generated code is the least settled part of the design, and the README says so plainly rather than pretending otherwise.

## Setting up the runtime and generating the code

The runtime goes into your Gradle build as an ordinary dependency.

```groovy
dependencies {
  implementation 'com.microsoft.thrifty:thrifty-runtime-jvm:3.1.0'
}
```

The repository block in the same example adds a Maven snapshots repository for pre-release builds. Generation happens either from the command line.

```bash
java -jar thrifty-compiler.jar --out=path/to/output file_one.thrift file_two.thrift file_n.thrift
```

Or through the Gradle plugin, which is configured with the com.microsoft.thrifty plugin and a thrifty block, with the README pointing to thrifty-gradle-plugin/README.md for the available options.

```groovy
apply plugin: 'com.microsoft.thrifty'
```

For Kotlin output the compiler takes a per-type flag.

```bash
java -jar thrifty-compiler.jar --kt-file-per-type --out=path/to/output example.thrift
```

The README's example file produces a service interface, an autogenerated client implementation, and one file per domain object, with the Kotlin file-per-type layout giving a separate file for the service, the client and each struct.

## What the generated Kotlin looks like

The generated data class shows the design more clearly than any description. A struct is a Kotlin data class implementing Struct, with each field annotated with @ThriftField carrying its field id and whether it is required, and each field marked @JvmField so it is a real public field on the JVM rather than a property with accessors.

```kotlin
public data class SearchResult(
  @JvmField
  @ThriftField(fieldId = 1, isRequired = true)
  public val url: String,

  @JvmField
  @ThriftField(fieldId = 2, isRequired = true)
  public val keywords: List<String>,

  @JvmField
  @ThriftField(fieldId = 3, isRequired = true)
  public val lastUpdatedMillis: Long
) : Struct {
```

The struct is immutable and has a minimal number of methods. It can be constructed only with all its required fields, all of them in this example, and an Adapter implementation handles reading and writing the struct to and from Protocols, with its body described as uninteresting but important serialization code. The service interface and the autogenerated client implementation are separate files, so the interface is something you can implement by hand for a test. The README notes the similarity to the protobuf classes generated by Square's Wire, and says it is intentional, with the design principles being immutable data, build-time validation, preferring fields over methods, and separating data representation from serialization.

## The interface definition language is standard Thrift

Nothing about the IDL changes. A service and its structured data are still defined in the Thrift Interface Definition Language, and the README's example is an ordinary Thrift file with a namespace declaration, two structs and a service with one method returning a list of results.

```thrift
namespace java com.foo.bar

struct Query {
  1: required string text,
  2: optional i64 resultsNewerThan
}
```

The struct is generated with public final fields, and the field ids and required or optional markers are what the compiler reads to decide both the wire layout and the shape of the Kotlin constructor. The README points to Thrift: The Missing Guide as an authoritative introduction to the IDL, which is the sensible way to learn the language itself since nothing in Thrifty changes it. This is worth stating plainly because it lowers the adoption cost: a team with existing Thrift IDL files does not have to rewrite its schemas, only change which compiler reads them.

## Where Thrifty is the wrong choice

Three cases stand out. The first is a greenfield decision. If you are choosing an RPC stack now, this repository carries a deprecation notice and its successor is a community fork rather than a Microsoft-maintained one, so the sensible path is to evaluate the fork or a different stack rather than to start on 3.1.0 here. The second is a service that needs TupleProtocol, which Thrifty does not support at present, and a codebase that still wants server-side generation on the Java side rather than Kotlin, since server-specific features are Kotlin-only and experimental. The third is a team that does not care about method count. If you are writing a server-side JVM service rather than an Android client, the accessor bloat is far less painful, and the 20,000 to 5,000 improvement is irrelevant to you because you were never counting methods. There is also a build-side consideration that the repository itself raises: the canonical compiler output is not Proguard-friendly, and while Thrifty reduces the problem, the annotations, the Adapter pattern and the Kotlin code generation all add machinery to a build that has to compile and shrink it.

## Conclusion

Adopt Thrifty only if you are already on an existing Thrift codebase and value the smaller generated API, and prefer the active fork referenced in the README for any new work. Skip it if you are choosing a Thrift implementation today, because this repository carries a deprecation notice pointing to benjamin-bader/thrifty. Before you migrate, check that your services avoid TupleProtocol, which Thrifty does not support, and confirm your build already handles Kotlin code generation, since server-side features are only supported there and are marked experimental.

## FAQ

### Is the microsoft/thrifty repository still maintained?

The README marks the repository as deprecated and links to issue 540, pointing to an active fork at github.com/benjamin-bader/thrifty. The last push to this repository was on 2026-09-23, and the most recent release here is 3.1.0 from 2022-12-13.

### What problem does Thrifty solve for Android?

The canonical Apache Thrift compiler generates verbose, method-heavy Java that is not very Proguard-friendly. Thrifty drops getters, setters, is-setters and Factories in favour of public final fields, which in the Outlook for Android codebase took the generated thrift classes from 20,000 methods down to 5,000.

### How do I generate Kotlin code with Thrifty?

Run the compiler with the per-type flag, for example `java -jar thrifty-compiler.jar --kt-file-per-type --out=path/to/output example.thrift`, or apply the com.microsoft.thrifty Gradle plugin. The per-type flag produces a separate file for the service, the client and each struct.

### Is Thrifty wire compatible with Apache Thrift?

Yes. The README states that Thrifty structs and clients are 100% compatible with Apache Thrift services. The differences are in the generated API: structs are immutable, always valid once built, default fields are treated as optional, TupleProtocol is unsupported, and server-specific features are Kotlin-only and experimental.

## Sources

- [License: Apache-2.0](https://github.com/microsoft/thrifty/blob/master/LICENSE)
- [microsoft/thrifty on GitHub](https://github.com/microsoft/thrifty)
- [Project website](https://github.com/benjamin-bader/thrifty)
- [README](https://github.com/microsoft/thrifty/blob/master/README.md)
- [Releases](https://github.com/microsoft/thrifty/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/microsoft-thrifty
