# Airbnb Mavericks: an Android state framework where the ViewModel is the only source of truth

> Mavericks (formerly MvRx) is Airbnb's Kotlin framework for Android screens. It pairs an immutable state object with a MavericksViewModel and a single invalidate() render callback, and it is installed as one Gradle dependency.

**airbnb/mavericks** — Mavericks: Android on Autopilot

- Repository: https://github.com/airbnb/mavericks
- Website: https://airbnb.io/mavericks/
- Stars: 5,926 · Forks: 510
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/airbnb-mavericks

## The problem Mavericks solves on an Android screen

Android screens tend to accumulate state in places that are hard to reason about: a field on a Fragment, a LiveData object, a value cached in an adapter, and a value inside the ViewModel. When a configuration change or a process death occurs, those copies drift apart. Mavericks answers this by making the state a single immutable data class and giving the view exactly one place to read it.

The README states the framework is used for nearly all product development at Airbnb, and that the original goal was not to invent another architecture pattern but to make building products easier and faster. That framing matters for who should care: this is not a general-purpose library for any Kotlin project. It targets Android screens with a lifecycle, a ViewModel and a view that must be re-rendered when data changes. A backend service or a Kotlin multiplatform module has no use for it.

## How state flows from MavericksViewModel to invalidate()

The mechanism is visible in the README's own example. You declare a data class that implements MavericksState. You subclass MavericksViewModel with that state type and pass an initial instance. Mutations go through setState, which takes a lambda over the current state and returns a copy. The view implements MavericksView and overrides invalidate(), which is where you read the latest state and update your widgets.

The README's comment on invalidate() is the important contract: it is called any time your state changes and the viewLifecycleOwner is STARTED. Two consequences follow. First, rendering is lifecycle-aware, so a backgrounded screen is not updated. Second, because state is immutable and replaced by copy, a change is a new object rather than a mutation in place, which is what makes the single render path tractable. The README does not describe the internal thread or subscription machinery, and it points readers to the docs site for the base ViewModel setup rather than spelling it out.

## Installing Mavericks from Maven Central with Gradle

Gradle is the only supported build configuration, so the install path is a single dependency line. The README gives this example, with x.y.z standing in for the version you choose:

```groovy
dependencies {
  implementation 'com.airbnb.android:mavericks:x.y.z'
}
```

Replace x.y.z with a published version. The README links to the Maven Central badge for the latest version rather than naming a number, so check that page before pinning. The repository also carries a versions.properties file and a settings.gradle at the top level, which is where the project's own module list lives if you want to see how the published artifacts are assembled.

A first real screen follows the shape in the README. Define the state, define the ViewModel, then render:

```kotlin
data class HelloWorldState(val title: String = "Hello World") : MavericksState

class HelloWorldViewModel(initialState: HelloWorldState) : MavericksViewModel<HelloWorldState>(initialState) {
    fun getMoreExcited() = setState { copy(title = "$title!") }
}
```

The README's fragment then obtains the ViewModel with fragmentViewModel() and overrides invalidate(). The comment in the README says to refer to the wiki for how to set up your base ViewModel, so the fragment wiring is not fully contained in the README itself. Expect to open the docs site before your first screen compiles.

## Where Mavericks gets in the way

The clearest constraint is the build system. The README says Gradle is the only supported build configuration. If your Android build is Bazel, Buck or something else, this framework is not aimed at you, and the README offers no alternative.

The second constraint is the documentation split. The README defers base ViewModel setup to the wiki and full documentation to the docs site, and it keeps a separate note that legacy documentation for MvRx 1.x lives in the wiki. A reader who lands on the README alone does not get a complete setup path. That is a real cost for evaluation: you cannot judge the framework from the repository front page.

Third, the module list at the top level shows how segmented the project has become. There is mvrx, mvrx-common, mvrx-compose, mvrx-hilt, mvrx-navigation, mvrx-rxjava2, mvrx-testing, mvrx-mocking, mvrx-launcher and a utils-view-binding module. Picking the right set for your stack is part of adoption, and the README does not map modules to use cases.

## Mavericks compared with a plain Android ViewModel

The obvious alternative is the ViewModel that ships with Android itself, holding LiveData or StateFlow fields and letting the view observe each one. The difference is structural rather than cosmetic. With a plain ViewModel you can expose several independent observables, and the view subscribes to whichever it needs. With Mavericks there is one state object and one invalidate() callback, and the README's comment ties that callback to the view lifecycle being STARTED.

That single-render model is easier to follow when a screen has many interdependent fields, because there is no question about which observable fired or in what order. It is more awkward when a screen genuinely has one independent value and no other state, since you still define a state class and a ViewModel for it. The framework also assumes a Fragment or Compose host: the README's example is a Fragment implementing MavericksView, and the repository ships a sample-compose module alongside sample-counter, sample-dogs, sample-todo and others, which indicates Compose is a first-class path rather than an afterthought.

## Release cadence, licence and the cost of upgrading

The release history shows v3.1.1 on 2026-09-25, v3.1.0 on 2026-02-07 and v3.0.13 on 2026-01-28, and the last push to the repository was on 2026-09-25. Releases cluster rather than arrive on a fixed schedule, which means the upgrade cost is paid when you choose to move, not on a cadence imposed by the project. The presence of a CHANGELOG.md and a RELEASING.md at the top level gives you a place to read what changed before bumping the version, and detekt.gradle and lint.xml indicate the project runs its own static analysis.

The licence is Apache-2.0. That permits commercial use and modification, and it includes a patent grant, but it also requires that you preserve the licence and notice files and state significant changes. This is a summary of the identifier, not legal advice; if you are redistributing a modified Mavericks, have counsel read the actual LICENSE file in the repository.

A practical upgrade cost is the module split. Moving from a plain ViewModel to Mavericks is a per-screen rewrite of the state and render path, not a drop-in swap, and the README's pointer to the wiki for base ViewModel setup means the migration instructions are not on the front page.

## Conclusion

Mavericks suits Kotlin Android teams already using Fragments or Compose who want one immutable state object per screen and a single render callback, and who accept Gradle as the only supported build configuration. It is the wrong choice if you need a non-Gradle build, or if your screens are better served by a plain ViewModel with no state container. Before adopting, verify that the artifact version you pin exists on Maven Central, that the mvrx module you need matches your UI stack (mvrx-compose for Compose, mvrx-navigation for navigation), and read the docs site for the base ViewModel setup the README defers to.

## FAQ

### How do I install Mavericks in an Android project?

Add the dependency to your Gradle build file as com.airbnb.android:mavericks with a published version, since the README states Gradle is the only supported build configuration. The README links to Maven Central for the latest version rather than naming one.

### What is the difference between Mavericks and MvRx?

They are the same project: the README titles it Mavericks (formerly MvRx). The README notes that legacy documentation for MvRx 1.x can still be found in the wiki, separate from the current docs site.

### How does Mavericks decide when to re-render a screen?

The view implements MavericksView and overrides invalidate(). The README's comment states that invalidate() is called any time your state changes and the viewLifecycleOwner is STARTED.

### Does Mavericks support Jetpack Compose?

The repository contains an mvrx-compose module and a sample-compose module at the top level, alongside the Fragment-based sample modules. The README itself only shows a Fragment example.

## Sources

- [airbnb/mavericks on GitHub](https://github.com/airbnb/mavericks)
- [License: Apache-2.0](https://github.com/airbnb/mavericks/blob/main/LICENSE)
- [Project website](https://airbnb.io/mavericks/)
- [README](https://github.com/airbnb/mavericks/blob/main/README.md)
- [Releases](https://github.com/airbnb/mavericks/releases)

---

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