Guidance for Mapperly compile-time source-generated object mapper. USE FOR: high-performance object mapping via source generation, compile-time mapping validation, zero-reflection mapping, AOT-compatible mapping, enum mapping, collection mapping. DO NOT USE FOR: runtime convention-based mapping with ProjectTo (use automapper), mapping configurations that change at runtime, mapping that requires DI-injected services.
Guidance for Mapperly compile-time source-generated object mapper. USE FOR: high-performance object mapping via source generation, compile-time mapping validation, zero-reflection mapping, AOT-compatible mapping, enum mapping, collection mapping. DO NOT USE FOR: runtime convention-based mapping with ProjectTo (use automapper), mapping configurations that change at runtime, mapping that requires DI-injected services.
Mapperly (Riok.Mapperly) is a compile-time object mapper for .NET that uses C# source generators to produce mapping code at build time. The generated code is equivalent to hand-written property assignments, with no runtime reflection, no expression tree compilation, and no hidden allocations. This makes Mapperly suitable for performance-critical paths, AOT (ahead-of-time) compilation scenarios, and applications where compile-time validation of mappings is important.
Mapperly is configured entirely through attributes on partial classes and methods. The source generator analyzes the source and destination types at compile time and emits the mapping implementation. If a property cannot be mapped (missing or incompatible types), the compiler produces a warning or error, catching mistakes during the build rather than at runtime.
Basic Mapper Definition
Define a partial class with the [Mapper] attribute. Declare partial methods for each mapping, and Mapperly generates the implementations.
Mapperly handles nullable types, collections, and dictionaries automatically.
using Riok.Mapperly.Abstractions;
namespaceMyApp.Mapping;
[Mapper]
publicpartialclassInventoryMapper
{
// Nullable source to nullable destinationpublicpartial WarehouseDto? MapWarehouse(Warehouse? warehouse);
// List mapping (generates a loop)publicpartial List<ItemDto> MapItems(List<Item> items);
// Dictionary mappingpublicpartial Dictionary<string, ItemDto> MapInventory(
Dictionary<string, Item> inventory);
// Array mappingpublicpartial ItemDto[] MapItemArray(Item[] items);
}
publicrecordWarehouse(string Name, string Location);
publicrecordWarehouseDto(string Name, string Location);
publicrecordItem(string Sku, string Name, int Quantity);
publicrecordItemDto(string Sku, string Name, int Quantity);
DI Registration and Usage
Mapperly mappers are plain classes with no runtime dependencies, making registration straightforward.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Register as singleton since mappers are stateless
builder.Services.AddSingleton<MyApp.Mapping.OrderMapper>();
builder.Services.AddSingleton<MyApp.Mapping.CustomerMapper>();
var app = builder.Build();
app.MapGet("/orders/{id:guid}",
async (Guid id, OrderMapper mapper, IOrderRepository repo) =>
{
var order = await repo.GetByIdAsync(id);
return order isnull
? Results.NotFound()
: Results.Ok(mapper.MapToDto(order));
});
app.Run();
Mapper Configuration
Global mapper settings are configured via the [Mapper] attribute.
Prefer Mapperly over AutoMapper for new projects and performance-sensitive paths because source-generated code has zero runtime overhead and catches mapping errors at compile time.
Define one mapper class per aggregate or feature area (e.g., OrderMapper, CustomerMapper) to keep mapping logic organized and discoverable.
Register mappers as singletons in the DI container since they are stateless and thread-safe, with no per-request state to manage.
Use [MapProperty] for name mismatches instead of renaming domain or DTO properties, preserving the natural naming of each layer.
Provide custom non-partial methods for complex value transformations (e.g., Money to string, DateTimeOffset to formatted string) and Mapperly will automatically use them for matching types.
Use [MapperIgnoreSource] and [MapperIgnoreTarget] to explicitly suppress warnings for properties that should not be mapped, such as PasswordHash or computed fields.
Review the generated source code (visible in the IDE or in obj/) to verify that Mapperly produces the expected assignments, especially for nested objects and collections.
Use [MapEnum(EnumMappingStrategy.ByName)] when source and destination enums have the same member names but different underlying values to avoid silent data corruption.
Enable ThrowOnMappingNullMismatch in the [Mapper] attribute during development to surface null-safety issues, then decide on production behavior based on your error-handling strategy.
Combine with AutoMapper only when you need ProjectTo for EF Core queries; use Mapperly for in-memory object mapping and AutoMapper exclusively for IQueryable projection.