Mapperly: compile-time object mapping for .NET without runtime reflection
A .NET source generator for generating object mappings. No runtime reflection.
At a glance
- What is it?
- Mapperly is a Roslyn source generator that writes the mapping code during the build, so the generated partial methods are plain C# you can read. Here is what it does, how to install it, and where it stops being the right tool.
- Who is it for?
- Mapperly fits teams that want mapping code visible in the build output and are willing to declare each mapper as a partial class. It is the wrong tool if you need mapping shapes decided at runtime from configuration, since the generator works from declarations it can see at compile time.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Mapperly solves: mapping code you cannot see
Object-to-object mapping in .NET usually means a library that resolves property names at runtime, walks the type metadata, and produces a destination object. That works, but the mapping rules live in configuration rather than in code the compiler checks. A renamed property or a type change surfaces as a runtime failure or a silently unmapped field, not as a build error.
Mapperly takes the other route. It is a .NET source generator, and the README states that because Mapperly creates the mapping code at build time, there is minimal overhead at runtime. The generated code is described as perfectly readable, which matters more than it sounds: you can open the generated file and confirm what each mapping method actually does.
The audience is .NET teams with DTO layers, API boundaries, or persistence models that need translating, and who already treat the build as the first line of defence. It is not aimed at people who want to describe mappings in JSON or a fluent configuration block at startup.
How the source generator turns a partial class into a mapping method
The mechanism is a Roslyn source generator. You write a partial class, mark it with the MapperAttribute from Riok.Mapperly.Abstractions, and declare partial mapping methods. The generator sees those declarations during compilation and emits the method bodies.
The README example is a CarMapper with one method, CarToCarDto, taking a Car and returning a CarDto. The body is not written by you. The generator produces it, matching members between the two types, and the resulting code compiles like any other C# in your assembly. There is no reflection call at runtime, because there is no lookup to perform: the assignments are already in the compiled method.
Two consequences follow from that design. First, a mapping that cannot be generated is a build-time diagnostic rather than a null reference in production. Second, the generated code is part of your repository's build output, so it can be reviewed, diffed and inspected with the same tools as hand-written code. The repository layout reflects this: there are src/, test/, benchmarks/ and samples/ directories, and a samples/Riok.Mapperly.Sample/ project alongside the solution file Riok.Mapperly.slnx.
Installing Riok.Mapperly and writing a first mapper
The package is published on NuGet as Riok.Mapperly. The README gives a single command to add it to a project.
dotnet add package Riok.MapperlyAfter that, declare the mapper. The README shows a partial class carrying the MapperAttribute and one partial method whose signature defines the mapping.
[Mapper]
public partial class CarMapper
{
public partial CarDto CarToCarDto(Car car);
}Using it is ordinary object construction and a method call. The README's usage snippet creates the mapper with new and calls the method, then checks a mapped value.
var mapper = new CarMapper();
var car = new Car { NumberOfSeats = 10, ... };
var dto = mapper.CarToCarDto(car);
dto.NumberOfSeats.ShouldBe(10);The README does not spell out the using directives in these snippets, so expect to add the namespace for MapperAttribute from Riok.Mapperly.Abstractions yourself. After the build, look for the generated file for CarMapper in your project's generated sources and read the emitted body. That inspection step is the fastest way to learn how the generator resolves member names before you trust it on a larger model.
Two release channels, and what the support policy actually promises
Mapperly ships through two channels, and the README is explicit about the difference. The stable channel, at mapperly.riok.app, carries production-ready releases and is subject to semantic versioning, with breaking changes reserved for major version bumps. The next channel, at next.mapperly.riok.app, carries preview releases that may contain breaking changes and are explicitly not subject to semantic versioning. The README frames the next channel as being for testing and early access.
The recent releases illustrate the split: v5.0.0-next.11, v5.0.0-next.10 and v5.0.0-next.9 are all prerelease tags from the next channel, dated 2026-09-01, 2026-07-13 and 2026-07-07. If you install the package without pinning, what you get depends on whether your NuGet feed configuration allows prerelease versions.
The support policy is narrower than many teams assume. The README states that only the latest version released on the stable channel is fully supported, and that the project strives to support all .NET versions currently supported by Microsoft. Strives is the operative word: this is a stated aim, not a guarantee tied to a specific version matrix. The repository was last pushed on 2026-09-21 and is not archived, so the codebase is moving, but the README does not publish a release cadence or a deprecation timeline for older majors. Upgrade guides for breaking changes are linked from the documentation under an upgrading category, which is the place to look before a major bump.
Where Mapperly is the wrong choice
The compile-time model has a hard boundary: the generator can only work from what it can see in your source. If your mapping shapes depend on runtime data, such as a tenant-specific field list loaded from a database, a partial class declaration cannot express that. A runtime-configured mapper is the better fit there, and no amount of generator configuration changes that.
The second limitation is the declaration overhead. Every mapper is a partial class and every mapping is a partial method signature you write by hand. On a large domain with dozens of DTO pairs, that is a real amount of boilerplate compared with a single profile class that registers many mappings at once. The generated code being readable is the payoff, but you pay for it in declarations.
Third, prerelease dependency risk. Teams that adopt the next channel to get features early are accepting, by the README's own description, versions that may break and are not covered by semantic versioning. The README also notes that only the latest stable release is fully supported, so pinning an older stable version puts you outside the supported set. Neither point is a defect, but both should be decided deliberately rather than by whatever version resolves first.
Finally, the README does not document rollback or a downgrade path if a generator version produces different output than expected. That absence is worth knowing before you commit a large model to it.
Mapperly against AutoMapper and Mapster
The comparison that matters is where the mapping decision is made. AutoMapper and Mapster are runtime mappers: you configure profiles or type adapters, and the library resolves members when the mapping executes. Mapperly resolves everything during compilation and emits the assignments into your assembly.
That difference shows up in three places. Build behaviour: a Mapperly mapping that cannot be generated fails the build, while a runtime mapper surfaces the problem when the code path runs. Inspection: Mapperly's output is C# in your project, whereas a runtime mapper's behaviour is the product of its configuration plus its internal resolution logic. Startup and call cost: the README's claim of minimal runtime overhead follows directly from there being no reflection step, and the repository includes a benchmarks/ directory, though the README does not publish numbers from it.
The trade-off runs the other way too. Runtime mappers let you change mappings without recompiling and can register many mappings from one configuration class. Mapperly asks for a partial class per mapper and a rebuild for every change. If your team treats mapping configuration as deployment-time data, Mapperly will feel rigid. If you treat it as code, the compiler checking it is the point.
Licence and the cost of keeping up
Mapperly is Apache-2.0 licensed, per the README and the LICENSE file at the repository root. That is a permissive licence, which generally means you can use it in commercial and closed-source projects; the usual Apache-2.0 obligations around notices and the patent grant still apply. This is not legal advice, and if your organisation has a licence review process, the LICENSE file is the authority to read rather than a summary.
The maintenance cost is mostly version tracking. Because only the latest stable release is fully supported, an old pinned version accumulates risk over time, and the upgrade guides exist precisely because major versions carry breaking changes. The next channel adds a second axis: preview releases are explicitly outside semantic versioning, so a preview tag can change behaviour without a major bump. Teams that pin exact versions and read the upgrade guide before each major move will spend less time on this than teams that float the version range.
There is also a commercial dimension. The README lists enterprise support, training, architecture consultation, custom feature development and performance reviews from the riok team, reachable through GitHub Discussions or [email protected], with priority support available through GitHub Sponsors. None of that is required to use the library, but it tells you the project has a funding model beyond volunteer time.
Editorial conclusion
Mapperly fits teams that want mapping code visible in the build output and are willing to declare each mapper as a partial class. It is the wrong tool if you need mapping shapes decided at runtime from configuration, since the generator works from declarations it can see at compile time. Before adopting it, check the upgrade guides for the major version you are moving from, confirm which .NET versions your target framework needs against the support policy, and decide whether the stable channel or the next channel matches your release process.
Frequently asked questions
How do you use Riok.Mapperly in a .NET project?
Add the Riok.Mapperly NuGet package, then declare a partial class marked with the MapperAttribute and a partial mapping method such as CarToCarDto. The generator fills in the method body at build time, and you use the mapper like any other class.
Is Mapperly free and open source?
Yes. The README states that Mapperly is Apache 2.0 licensed, and the repository carries a LICENSE file at its root. The project also offers paid enterprise support and consulting separately from the library itself.
Is Mapperly open source?
Yes, it is published under the Apache 2.0 licence and the source lives in the riok/mapperly repository on GitHub. The README links to the LICENSE file and to the contributing documentation.
How does Mapperly compare with AutoMapper and Mapster?
AutoMapper and Mapster resolve mappings at runtime from configuration, while Mapperly is a source generator that emits the mapping code during the build. That means Mapperly's mapping failures appear as build diagnostics and its output is readable C#, at the cost of declaring a partial class and method per mapping.
What is the difference between Mapperly and manual mapping?
Manual mapping is code you write and maintain by hand for each type pair. Mapperly generates that code from a partial method declaration, so the assignments do not have to be written or kept in sync manually, but you still declare the mapper class and method signature yourself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/riok-mapperly)