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.
Every- and All-Level Disable
Section titled “Every- and All-Level Disable”Disable AutoMap inside an every or all block:
projection User => UserReadModel every no automap LastUpdated = $eventContext.occurredAutoMap cannot be toggled inside an individual from block — it is controlled at the projection, children, or nested level.
Join-Level Disable
Section titled “Join-Level Disable”Disable AutoMap within a join’s with blocks:
join Group on GroupId with GroupCreated no automap Name = name with GroupRenamed no automap Name = nameChildren-Level Disable
Section titled “Children-Level Disable”Disable AutoMap for children collections:
children members identified by 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
Consider a UserRegistered event with the properties Name, Email, and Age, projected onto a read model with the properties Name, Email, Age, and IsActive:
projection User => UserReadModel from UserRegistered IsActive = trueWith default AutoMap, Name, Email, and Age are automatically copied. IsActive does not exist on the event, so it must be set explicitly.
Scope and Precedence
Section titled “Scope and Precedence”- Projection-level
no automapdisables AutoMap for all events - Every/All-level
no automapapplies within thateveryorallblock - Explicit mappings always override AutoMap values when both exist
- Join-level
no automapapplies within the individualwithblock - Children-level
no automapapplies to child events - Default is Enabled - AutoMap works unless explicitly disabled
AutoMap cannot be toggled inside an individual from block.
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
join Profile on ProfileId with 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 with CustomerCreated no automap CustomerName = name with CustomerUpdated no automap CustomerName = nameChildren with Selective Disable
Section titled “Children with Selective Disable”projection Group => GroupReadModel from GroupCreated # AutoMap enabled
children members identified by 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