Auto-Map
AutoMap automatically copies properties with matching names from the event to the read model, reducing boilerplate when property names align.
AutoMap is enabled by default for all projections. To disable it, use the no automap directive.
Default Behavior
Section titled “Default Behavior”By default, all property mappings automatically copy matching properties:
projection User => UserReadModel from UserRegistered IsActive = trueThis auto-maps all matching properties from UserRegistered, then applies the explicit IsActive mapping.
Disabling AutoMap
Section titled “Disabling AutoMap”Use no automap to disable automatic property mapping when needed.
Projection-Level Disable
Section titled “Projection-Level Disable”Disable AutoMap for the entire projection:
projection User => UserReadModel no automap
from UserRegistered Name = name Email = emailAll properties must be mapped explicitly.
Event-Level Disable
Section titled “Event-Level Disable”Disable AutoMap for a specific event:
projection User => UserReadModel from UserRegistered no automap Name = name Email = email
from UserUpdated # AutoMap still enabled here UpdatedAt = $eventContext.occurredJoin-Level Disable
Section titled “Join-Level Disable”Disable AutoMap within join blocks:
join Group on GroupId events GroupCreated, GroupRenamed no automap Name = nameChildren-Level Disable
Section titled “Children-Level Disable”Disable AutoMap for children collections:
children members id userId no automap
from UserAddedToGroup UserId = userId Role = roleCombining with Explicit Mappings
Section titled “Combining with Explicit Mappings”AutoMap runs first, then explicit mappings override or add properties:
from UserRegistered IsActive = true CreatedAt = $eventContext.occurredIf the event has Name and Email properties, they’re auto-mapped. Then IsActive and CreatedAt are set explicitly.
Matching Rules
Section titled “Matching Rules”AutoMap matches properties when:
- Property names are identical (case-sensitive)
- Both source (event) and target (read model) have the property
- Types are compatible
Example event:
public record UserRegistered(string Name, string Email, int Age);Example read model:
public class UserReadModel{ public string Name { get; set; } public string Email { get; set; } public int Age { get; set; } public bool IsActive { get; set; }}With default AutoMap, Name, Email, and Age are automatically copied. IsActive must be set explicitly.
Scope and Precedence
Section titled “Scope and Precedence”- Projection-level
no automapdisables AutoMap for all events - Event-level
no automapapplies only to that specific event - Explicit mappings always override AutoMap values when both exist
- Join-level
no automapapplies to joined events - Children-level
no automapapplies to child events - Default is Enabled - AutoMap works unless explicitly disabled
Examples
Section titled “Examples”Default AutoMap
Section titled “Default AutoMap”projection Product => ProductReadModel from ProductCreated # Name, Price, Description auto-mapped if they exist CreatedAt = $eventContext.occurredDisable AutoMap Entirely
Section titled “Disable AutoMap Entirely”projection Order => OrderReadModel no automap
from OrderPlaced OrderId = orderId CustomerId = customerId Total = total Status = "Pending"Mixed Approach
Section titled “Mixed Approach”projection User => UserReadModel from UserRegistered # AutoMap enabled (default) IsActive = true
from UserProfileUpdated no automap # Must map everything explicitly Name = fullName Email = emailAddressProjection-Level Disable with Event-Level Override
Section titled “Projection-Level Disable with Event-Level Override”projection User => UserReadModel no automap
from UserRegistered Name = name Email = email
from UserDeactivated # Still disabled - no automap is inherited IsActive = false DeactivatedAt = $eventContext.occurredJoin with Disabled AutoMap
Section titled “Join with Disabled AutoMap”projection Order => OrderReadModel from OrderPlaced # AutoMap enabled
join Customer on CustomerId events CustomerCreated, CustomerUpdated no automap CustomerName = nameChildren with Selective Disable
Section titled “Children with Selective Disable”projection Group => GroupReadModel from GroupCreated # AutoMap enabled
children members id userId no automap
from UserAddedToGroup UserId = userId Status = "Active"When to Disable AutoMap
Section titled “When to Disable AutoMap”Disable AutoMap when:
- Event and read model property names don’t align
- You need explicit control over all mappings
- Property transformations are required
- You want to be explicit for code clarity
- Only a few properties actually match
Keep AutoMap (default) when:
- Event and read model property names align
- You want to reduce boilerplate
- Properties have compatible types
- You’re following naming conventions
- Most properties map directly
Best Practices
Section titled “Best Practices”- Leverage the Default: AutoMap reduces boilerplate for most cases
- Disable Selectively: Use
no automaponly when needed - Document Assumptions: AutoMap relies on naming conventions being consistent
- Event-Level for Precision: Apply
no automapper event if only some events need explicit control - Explicit Overrides: Let AutoMap handle the bulk, use explicit mappings for specifics
Migration from Explicit AutoMap
Section titled “Migration from Explicit AutoMap”If you’re updating existing projections that used automap directive:
- Remove all
automapdirectives - they’re now redundant (default behavior) - Add
no automaponly where you previously didn’t haveautomap - Existing explicit mappings continue to work and override auto-mapped values