Implements a pure, algebraic migration system for ZIO Schema that represents
structural transformations between schema versions as first-class, serializable
data. Unlike traditional migration approaches, this system uses no functions,
closures, or reflection - migrations are pure ADTs that can be stored,
inspected, and applied dynamically.
Key Features
- Pure Data Migrations: All migrations are represented as case classes with no
closures
- Fully Serializable: DynamicMigration can be stored in registries, databases,
or files
- Compile-Time Validation: MigrationBuilder.withFieldTracking ensures all
fields are handled
- Bidirectional: Every migration has a structural reverse
- Path-Based Actions: All operations specify location via DynamicOptic
- Introspectable: Migration logic can be inspected, transformed, and optimized
API Overview
// Build a type-safe migration
val migration = MigrationBuilder.withFieldTracking[PersonV1, PersonV2]
.renameField(select(_.name), select(_.fullName))
.keepField(select(_.age))
.addField(select(_.country), "US")
.build // Only compiles when all fields are handled
// Apply migration
migration.apply(v1) // Right(PersonV2(...))
// Reverse migration
migration.reverse.apply(v2) // Right(PersonV1(...))
Migration Actions
Category: Record
Actions: AddField, DropField, Rename, TransformValue, Mandate, Optionalize,
ChangeType
────────────────────────────────────────
Category: Enum
Actions: RenameCase, TransformCase
────────────────────────────────────────
Category: Collection
Actions: TransformElements, TransformKeys, TransformValues
Files Added
- Core Types: MigrationError, MigrationAction, DynamicMigration, Migration,
SchemaFields, FieldSelector, Resolved, PrimitiveConversions
- Type-Level: FieldSet (Scala 2 & 3)
- Macros: SelectorMacros, SchemaFieldsMacros, MigrationBuilderMacros (Scala 2 &
- Builder: MigrationBuilder (Scala 2 & 3)
- Documentation: docs/reference/migration.md
Design Decisions
- Non-inline builder methods: Only select() and withFieldTracking are inline
macros. All builder methods are regular methods with type parameters, ensuring
builders work correctly when stored in vals.
- Two-layer architecture:
- DynamicMigration - Untyped, fully serializable core
- Migration[A, B] - Typed wrapper with schemas
- Resolved expressions: Pure data representations of value computations
(Literal, Identity, FieldAccess, Convert, Concat, etc.)
Test Coverage
1000+ tests across 24 spec files covering:
- Core migration operations
- Builder API and field tracking
- All migration action types
- Bidirectional migrations
- Error handling and diagnostics
- Algebraic properties (identity, associativity)
- Edge cases and boundaries
- Property-based tests
fixes #519
/claim #519