The Best Way to Map Objects in .NET in 2024 (and Beyond)
Learn the best way to map objects in .NET: manual mapping, Mapperly source generators, and why teams are moving away from AutoMapper after it went commercial.
Think about ordering food at a restaurant. The kitchen has a big recipe card with everything: the supplier name, the cost of each item, the chef's secret notes. But the menu you get at your table is much smaller. It only shows the dish name, a short description, and the price. Someone takes the full kitchen card and copies just the right parts onto the customer menu.
That copying job is exactly what object mapping is in .NET. You have one object full of details (like a database row), and you need to copy some of its data into another object that has a different shape (like the response your API sends back). You map the fields from one to the other.
In this guide you will learn the different ways to do this in .NET, which one is best for your project, and why so many teams changed their plan in 2024 and 2025.
Why do we even need mapping?
In a real app you usually have more than one kind of object for the "same" thing.
- An entity is the object that matches your database table. It may have secret fields like a password hash or an internal note.
- A DTO (Data Transfer Object) is the object you send out of your API or take in. It only has the fields the outside world is allowed to see.
You never want to send your database entity straight out. It might leak private data, and it ties your API shape to your database shape. So you copy the safe fields into a DTO. That copy step is mapping.
Here is a tiny example. We have an Order entity and an OrderResponse DTO.
// The full entity that lives in the database.
public class Order
{
public Guid Id { get; set; }
public string CustomerName { get; set; } = "";
public decimal Total { get; set; }
public string InternalNote { get; set; } = ""; // secret, do not send out
public DateTime CreatedAt { get; set; }
}
// The smaller object we send back from the API.
public record OrderResponse(
Guid Id,
string CustomerName,
decimal Total,
DateTime CreatedAt);Notice that InternalNote is not in OrderResponse. That is the whole point. Mapping lets us pick only the safe fields.
The three main ways to map in .NET
There are three common approaches. Let us meet them one by one.
- Manual mapping — you write the copy code yourself.
- Source-generated mapping — a tool writes the copy code for you at build time. Mapperly and Mapster (with its tool) live here.
- Reflection-based mapping — a library copies fields at run time by inspecting types. AutoMapper is the famous one here.
Choosing a mapping approach
Steps
Start
You need to map objects
Small?
Few, simple objects
Manual
Just write plain C#
Many DTOs?
Lots of large objects
Mapperly
Generate code at build
Reflection
Older default, now paid for big teams
Let us look at each one closely.
Approach 1: Manual mapping
Manual mapping means you simply write the copy code by hand. No library at all.
public static class OrderMapping
{
// Plain C#. Easy to read. Easy to debug.
public static OrderResponse ToResponse(this Order order)
{
return new OrderResponse(
order.Id,
order.CustomerName,
order.Total,
order.CreatedAt);
}
}Then in your code you write order.ToResponse(). That is it.
People sometimes think manual mapping is "old fashioned" or "not clever enough". That is not true. Manual mapping has real strengths:
- It is the fastest option. There is no extra magic at run time.
- It is compile-time safe. If you rename a field, the build breaks and tells you right away.
- It is easy to debug. You can put a breakpoint on any line.
- It needs no library, so nothing to update and nothing to pay for.
The only real downside shows up when you have many big objects. Writing the same kind of copy code 50 times gets boring and you can make small mistakes. That is where the next approach helps.
Approach 2: Source-generated mapping (Mapperly)
A source generator is a tool that runs while your project builds. It looks at your code and writes extra C# code for you. The generated code becomes part of your program, just like code you typed yourself.
Mapperly is the most popular mapping source generator. You describe the mapping with a small class, and Mapperly writes the actual copy method during the build.
using Riok.Mapperly.Abstractions;
[Mapper]
public partial class OrderMapper
{
// Mapperly fills in the body of this method at build time.
public partial OrderResponse ToResponse(Order order);
}The word partial is the key. You leave the method empty. Mapperly generates the full body in another file. The generated code is plain, readable C# that does direct property assignment, like the manual version above. You can even open it and read it.
Because the code is generated at build time, Mapperly gives you the best of both worlds:
- It is fast, almost as fast as hand-written code, because there is no reflection at run time.
- It is compile-time safe. If a field does not match, you get a warning or error during the build.
- It is free under the Apache 2.0 licence.
- It saves you from writing repetitive copy code.
Mapster is another tool in this family. It can also generate code at compile time using Mapster.Tool, and it is known for being fast and flexible. Mapperly and Mapster are both good picks; this guide leans on Mapperly because its generated code is very easy to read.
Approach 3: Reflection-based mapping (AutoMapper)
For many years, AutoMapper was the default choice in .NET. It uses reflection, which means it inspects your objects at run time and copies matching fields. You set up "profiles" that tell it how the two types line up.
This was convenient. You did not write copy code, and AutoMapper figured out most fields by name. But reflection has costs:
- It is slower because the work happens at run time, every time you map.
- It uses more memory.
- It is not compile-time safe. If a field is missing, you often find out only when the app runs and a test fails or a value comes back empty.
- The mapping code is hidden, so it is harder to step through and debug.
In one common benchmark mapping 100,000 objects, Mapperly finished in about 28.6 ms while AutoMapper took about 36.4 ms. That is roughly 22% faster, with less memory used. Numbers vary by machine and version, but the pattern is steady: generated code beats reflection.
The big 2024 and 2025 change: AutoMapper went commercial
Here is the news that made many teams rethink their choice.
Through 2024, AutoMapper was free and open source. Then, in July 2025, Jimmy Bogard, the creator, launched commercial editions of AutoMapper and MediatR under a company called Lucky Penny Software. MassTransit, another well-known library, also moved toward a commercial model around the same time.
The important details:
- AutoMapper and MediatR are still free for individuals and for companies with less than 5 million USD in yearly revenue.
- Larger teams now need a paid licence. Pricing is by team size, for example a Standard tier for small teams and higher tiers for bigger ones.
- If you already use it, your existing version keeps working. You do not have to change anything overnight.
So why did this push teams to alternatives? Because a free, open library felt safe to depend on forever. Once money and revenue limits enter the picture, teams worry about future costs and rules. Many decided it was simpler to move to a free, source-generated mapper like Mapperly, which is fast, modern, and Apache 2.0 licensed.
Why teams moved off AutoMapper
Steps
Free for years
AutoMapper was the default
Went commercial 2025
Paid for larger teams
Revenue limits
5M USD rule applies
Look at options
Compare free, fast mappers
Pick Mapperly
Source-generated and free
Side-by-side comparison
Here is a simple table to compare the three approaches.
| Approach | Speed | Compile-time safe | Cost | Best for |
|---|---|---|---|---|
| Manual mapping | Fastest | Yes | Free | Small projects, few objects |
| Mapperly / Mapster | Very fast | Yes | Free | Many objects, large apps |
| AutoMapper (reflection) | Slower | No | Free under 5M USD, else paid | Existing projects already using it |
And here is how the workflow differs for each.
| Step | Manual | Mapperly | AutoMapper |
|---|---|---|---|
| Where mapping runs | You write it | Build time | Run time |
| Add a library? | No | Yes (free) | Yes (paid for big teams) |
| See the copy code? | Yes | Yes, generated | No, hidden |
| Error shows up | At build | At build | At run time |
A complete Mapperly example
Let us put Mapperly to work with a slightly bigger example. Say we also want a list of order items in the response.
using Riok.Mapperly.Abstractions;
public class OrderItem
{
public string ProductName { get; set; } = "";
public int Quantity { get; set; }
}
public record OrderItemResponse(string ProductName, int Quantity);
[Mapper]
public partial class OrderMapper
{
// Map a single order. Mapperly handles the nested list too.
public partial OrderResponse ToResponse(Order order);
// Mapperly also generates this helper for the list items.
public partial OrderItemResponse ToItemResponse(OrderItem item);
}Mapperly notices the nested list and wires it up for you. The generated code is just direct assignments and a simple loop, so it stays fast and readable.
So, what is the best way?
There is no single winner for every project. But here is honest, simple advice for 2024 and beyond:
- Small project, few objects? Use manual mapping. It is the simplest and fastest, and you avoid any library.
- Bigger project with many DTOs? Use Mapperly (or Mapster). You get compile-time safety and great speed without writing the same copy code again and again.
- Already on AutoMapper and under the revenue limit? You can stay for now. But for new projects, prefer a source generator so you are not tied to a paid model later.
The clear trend is away from run-time reflection and toward code that is generated or written by hand. That code is faster, safer, and easier to read.
References and further reading
- Mapperly - GitHub (riok/mapperly) — the source generator, docs, and examples.
- AutoMapper and MediatR Commercial Editions Launch Today (Jimmy Bogard) — the official announcement and pricing.
- The Best Way To Map Objects in .NET in 2024 (antondevtips) — a community comparison of mapping options.
- Best Free Alternatives to AutoMapper - Why We Moved to Mapperly (ABP.IO) — a real team's migration story.
Quick recap
- Mapping copies data from one object (like a database entity) into another object of a different shape (like a DTO). It is like copying the right parts of a kitchen recipe card onto a customer menu.
- There are three main ways: manual mapping, source-generated mapping (Mapperly, Mapster), and reflection-based mapping (AutoMapper).
- Manual mapping is fast, safe, free, and great for small projects.
- Mapperly writes mapping code at build time. It is fast, free (Apache 2.0), and compile-time safe. It is the strong pick for larger apps.
- AutoMapper uses reflection, which is slower and not compile-time safe. In July 2025 it went commercial, free only for teams under 5 million USD in revenue.
- For new projects, prefer manual mapping or a source generator like Mapperly. The .NET world is moving away from run-time reflection.
Related Posts
Strongly Typed IDs in .NET: A Safer Way to Identify Entities
Learn how strongly typed IDs in .NET stop you from mixing up entity identifiers, catch bugs at compile time, and work cleanly with EF Core.
How to Write Better and Cleaner Code in .NET
A beginner-friendly guide to writing better, cleaner C# and .NET code using clear names, small methods, modern C# 14 features, and simple structure.
Building Semantic Search With Amazon S3 Vectors and Semantic Kernel
A beginner-friendly guide to building semantic search in .NET using Amazon S3 Vectors for cheap storage and Semantic Kernel for embeddings.
What Is Vector Search? A Concise Guide for .NET Developers
A simple, friendly guide to vector search for .NET developers: embeddings, similarity, nearest neighbors, and how to build it with Microsoft.Extensions.VectorData.
How I Implemented Full-Text Search on My Website with EF Core
A simple, beginner-friendly guide to adding fast full-text search to your .NET website using EF Core with SQL Server and PostgreSQL.
How to Scale Long-Running API Requests in .NET: A Beginner's Guide
Learn how to handle slow, long-running API requests in .NET using the 202 Accepted pattern, background services, channels, and status polling.