# MoshiX collects the extensions that plain Moshi does not ship

> MoshiX is a repository of five separate Kotlin libraries that extend Moshi, from a Kotlin IR implementation and code generation to reflective sealed class support and adapters for immutable collections. The README is a short index rather than a guide, so the value here is in what each module actually replaces.

**ZacSweers/MoshiX** — Extensions for Moshi including IR plugins, moshi-sealed, and more.

- Repository: https://github.com/ZacSweers/MoshiX
- Stars: 543 · Forks: 41
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/zacsweers-moshix

## Five libraries in one repository

MoshiX is described as extensions for Moshi, and the repository is really an index of five separate modules rather than one library. Each has its own directory, its own artifact and its own purpose.

`moshi-ir` is a Kotlin IR implementation of Moshi, and it also provides the moshi-sealed code generation. `moshi-adapters` is a collection of custom adapters for Moshi. `moshi-immutable-adapters` is a collection of Moshi adapters for kotlinx.collections.immutable. `moshi-metadata-reflect` is a kotlinx-metadata based implementation of `KotlinJsonAdapterFactory`. And `moshi-sealed` holds reflective and code gen implementations for serializing Kotlin sealed classes via Moshi polymorphic adapters.

That last one, `moshi-sealed`, is where most people arrive, because sealed classes are the case where Moshi's generated adapters stop being straightforward: a sealed hierarchy needs a discriminator and a lookup of the permitted subclasses, and the built-in generated adapter cannot do it.

The repository topics give a sense of the technique set involved: annotation-processor, code-generation, ir, json, kapt, kotlin, kotlin-compiler-plugin, kotlin-reflect, kotlin-symbol-processor, kotlinpoet, kotlinx-metadata, ksp, moshi, reflection and sealed. That is the vocabulary of the Kotlin toolchain, and it tells you the project works at the compiler plugin and annotation processing level rather than only at the runtime library level.

The project is Kotlin, Apache 2.0 licensed, with the copyright held by Zac Sweers since 2020. The releases are 0.38.0 from 2026-10-05, 0.37.0 from 2026-07-02 and 0.36.0 from 2026-06-03, and the last push was on 2026-10-20.

The honest note about this repository is that its README is an index. There is no architecture guide, no tutorial and no comparison of the options inside each module, so the documentation for each library lives with that library, and the repository root is mostly a map of where to look.

## moshi-sealed, in reflective and generated form

The `moshi-sealed` module is described as reflective and code gen implementations for serializing Kotlin sealed classes via Moshi polymorphic adapters. Two implementations of the same problem is the design decision worth understanding, because the choice between them is a real trade-off.

Moshi's polymorphic adapter model expects a discriminator, usually a field whose value identifies which subtype was read, and a way to find the subtypes. For a sealed hierarchy in the same package, the compiler knows the permitted subclasses, and Moshi's own generated adapter can find them at compile time. The problem arises when the sealed class and its subclasses live in different modules or different packages, because then the codegen in one module cannot see the others, and the adapter has to look them up at run time.

The reflective implementation handles that by resolving the hierarchy at run time. That works across module boundaries and needs no build step, at the cost of reflection and of the run-time lookup.

The code gen implementation takes the other route and generates the adapter with the subclass knowledge resolved at compile time. That is faster at run time and has no reflection cost, but it depends on the generator seeing the whole hierarchy, which is exactly the constraint the reflective one exists to work around.

The module name `moshi-sealed` sits alongside `moshi-ir`, and the moshi-ir entry in the README says it is a Kotlin IR implementation of Moshi and moshi-sealed code gen. So the code generation path for sealed classes is delivered through the Kotlin IR plugin rather than through the older annotation processing route. That is a meaningful detail: the IR backend is the modern way to write a Kotlin compiler plugin, and it is why the repository topics include both `kotlin-compiler-plugin` and the older `kapt` and `annotation-processor` terms, since the project spans both eras of the toolchain.

For anyone choosing between the two implementations, the practical test is whether your sealed hierarchy is fully visible at compile time in one module. If it is, the generated adapter is the better answer. If it is not, the reflective one is the only one that will find the subclasses.

## Reflection without pulling in kotlin-reflect

The `moshi-metadata-reflect` module is the one with the most specific promise, and it is worth reading the sentence carefully.

It is a kotlinx-metadata based implementation of `KotlinJsonAdapterFactory`, and the stated effect is that this allows for reflective Moshi serialization on Kotlin classes without the cost of including kotlin-reflect.

That is a specific and real problem. Moshi's reflective adapters need runtime information about Kotlin classes, and the usual way to get it is `kotlin-reflect`, which is a large dependency that adds start-up cost and memory to an application that only wanted JSON. The whole point of Moshi's design is that you can use it without reflection, and the code generation path avoids kotlin-reflect. But when you have classes you cannot generate adapters for, such as ones from a third party library, you are pushed back toward kotlin-reflect.

This module takes the middle path. It reads the Kotlin metadata that is already in the compiled class files, using the kotlinx-metadata library, and uses that to drive the reflective adapter. So you get reflection-style behaviour without shipping kotlin-reflect, and the metadata is already there because the Kotlin compiler embedded it.

The trade is that you are depending on an implementation detail of the compiled output, namely the presence and shape of the Kotlin metadata, rather than on the reflection API. That is a less stable contract than kotlin-reflect itself, and it is why the module is separate from the core Moshi extension rather than folded into it.

The repository topics list `kotlinx-metadata` and `kotlin-reflect` separately, and there is a `moshix-runtime/` directory at the top level of the repository alongside the five published modules, which suggests a shared runtime component used by more than one of them.

## The adapter collections

The two adapter modules are the least interesting to describe and the most immediately useful, because they remove code you would otherwise write.

`moshi-adapters` is a collection of custom adapters for Moshi. `moshi-immutable-adapters` is a collection of Moshi adapters for kotlinx.collections.immutable, which is the persistent collections library for Kotlin, the one that gives you structural sharing on updates.

The second one exists because of a specific gap. kotlinx.collections.immutable has its own collection types, `PersistentList`, `PersistentSet` and `PersistentMap`, and they are not the same types as the standard `List`, `Set` and `Map`. A Moshi adapter generated for a `List` property will not accept a `PersistentList`, because the type is different, so an application that uses persistent collections needs adapters for them or it needs to convert at the boundary.

That is a recurring pattern with Moshi, and it is the reason a repository of adapters is useful at all. Moshi is deliberately small, and the extension surface around it is where the practical work goes: a type that Moshi does not know how to handle needs an adapter, and every project ends up writing some of the same ones.

The `moshi-immutable-adapters` module also shows a pattern in how these libraries are built. The collection types in kotlinx.collections.immutable are interface types with a hidden implementation, so an adapter cannot construct one by calling a constructor directly. The usual solution is to build the standard collection and then convert it with the library's own factory function, which is a small amount of code that is easy to get wrong and worth having in one tested place.

Neither module is documented in the root README beyond its one-line description, so the detail of which adapters exist in each has to come from the module directories themselves.

## The build, the release process and the development feed

The repository layout is the standard Gradle multi-project arrangement, and it is where the tooling story shows.

At the root there is `build.gradle.kts` and `settings.gradle.kts`, the `gradlew` and `gradlew.bat` wrappers, a `gradle/` directory, `gradle.properties`, a `config/` directory for shared build configuration, and `scripts/` for helper scripts. There is also `checksum.sh`, `publish.sh` and `release.sh` as three separate shell scripts, plus `RELEASING.md` documenting the release process and `CHANGELOG.md`.

Two files are worth singling out because they say something specific. `compiler-version-aliases.txt` is the mechanism for a Kotlin compiler plugin project to track which compiler versions it supports, which is a genuine problem for IR plugins because they are tied to a compiler version. And `renovate.json` is there for automated dependency updates, which matters for a project whose whole purpose is tracking the Kotlin toolchain.

The `.kempt.toml` file is a configuration for Kempt, a tool for publishing Kotlin multiplatform libraries with the right metadata across targets, which is a reasonable fit for a set of libraries that mostly target the JVM but are consumed by multiplatform projects.

Publishing is handled with `publish.sh` and `release.sh`, and the development builds are published to Sonatype's snapshots repository, at the path for the `dev.zacsweers.moshix` group. That is the standard place to pick up a build of the current development state before a release lands, which is what you want when you are tracking a Kotlin compiler plugin and the released version does not yet support the compiler you are on.

The licence is Apache 2.0, with the full text in `LICENSE.txt` and the notice carrying the copyright of Zac Sweers from 2020.

## Conclusion

Adopt MoshiX when you are on Moshi and need one of the things it deliberately leaves out, sealed class polymorphism, reflection without kotlin-reflect, or an immutable collection adapter. Do not adopt it as a drop-in Moshi upgrade, since these are separate artifacts with separate versions rather than a replacement library. Verify first which module you actually need, since moshi-sealed in particular offers both a reflective and a generated implementation with different trade-offs, that your Kotlin compiler version is one the moshi-ir plugin is built for, and that the version you take is 0.38.0, released on 2026-10-05, with the last push on 2026-10-20.

## FAQ

### What is MoshiX?

MoshiX is a collection of extensions for Moshi, made up of five separate modules: moshi-ir, a Kotlin IR implementation of Moshi and the moshi-sealed code generation; moshi-adapters, custom adapters for Moshi; moshi-immutable-adapters, adapters for kotlinx.collections.immutable; moshi-metadata-reflect, a kotlinx-metadata based KotlinJsonAdapterFactory; and moshi-sealed, reflective and code gen implementations for sealed class serialization.

### How does moshi-sealed handle Kotlin sealed classes?

It provides both reflective and code gen implementations for serializing sealed classes via Moshi polymorphic adapters, and the code generation path is delivered through the moshi-ir Kotlin IR plugin rather than through annotation processing.

### What does moshi-metadata-reflect avoid?

It is a kotlinx-metadata based implementation of KotlinJsonAdapterFactory that allows reflective Moshi serialization on Kotlin classes without the cost of including kotlin-reflect, using the Kotlin metadata already embedded in the compiled classes.

### Where do I get a development build of MoshiX?

Development builds are published to Sonatype's snapshot repository, under the group path for dev.zacsweers.moshix, and the README links to it. The published releases are 0.38.0 from 2026-10-05, 0.37.0 from 2026-07-02 and 0.36.0 from 2026-06-03.

### What licence does MoshiX use?

Apache 2.0, with the copyright of Zac Sweers from 2020 and the full licence text in the LICENSE.txt file at the repository root.

## Sources

- [Issues](https://github.com/ZacSweers/MoshiX/issues)
- [License: Apache-2.0](https://github.com/ZacSweers/MoshiX/blob/main/LICENSE)
- [README](https://github.com/ZacSweers/MoshiX/blob/main/README.md)
- [Releases](https://github.com/ZacSweers/MoshiX/releases)
- [ZacSweers/MoshiX on GitHub](https://github.com/ZacSweers/MoshiX)

---

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