Zorphy is a powerful code generation package for Dart/Flutter that provides clean, immutable class definitions with advanced features including copyWith methods, JSON serialization, equality, toString, inheritance support, and sophisticated patch mechanisms.
Sponsor
Thanks to ZikZak AI for sponsoring this project!
ZikZak AI is an AI-Powered Price Comparison app that you scan barcodes, and discover amazing savings instantly. Your personal shopping assistant that never sleeps.
📖 Documentation
Visit the official documentation at arrrrny.github.io/zorphy for detailed guides, examples, and API references.
🏷️ Field-Selector CopyWith - copyWithField(Field<E, T> field, T value) replaces a single field via the typed Field selector; passing null to a nullable field preserves the current value
🎯 Function-based CopyWith - Optional function-based copyWith for computed updates
🔧 Patch System - Advanced patching mechanism for partial updates with nested support
📦 JSON Serialization - Full toJson/fromJson support with polymorphic type handling
⚖️ Equality - Auto-generated == operator and hashCode
📝 toString - Meaningful string representations for debugging
🔐 Sealed Classes - Support for sealed classes with exhaustiveness checking
🌳 Self-Referencing Types - Handle tree structures and hierarchical data
🏭 Factory Methods - Support for custom factory constructors
🧬 Inheritance & Polymorphism - Multiple inheritance, generics, and interfaces
🔢 Enum Support - Full enum integration with JSON serialization
📊 CompareTo - Generate comparison methods showing differences between instances
🔄 ChangeTo - Convert between related types in inheritance hierarchies
🤖 AI-Friendly CLI - Command-line tool optimized for AI agents and developers
🔌 MCP Server - Model Context Protocol server for agentic integration
⚖️ Zorphy vs Freezed
Both generate immutable data classes. Zorphy goes further — it is a full
entity toolkit with a nested patch system, filter/query descriptors,
compareTo diffs, and an AI-agent CLI/MCP server.
Capability
zorphy 2.0
freezed 3.2.5
Immutable data classes + copyWith
✅
✅
Function-based copyWith (copyWithFn)
✅ opt-in (ZorphyPreset.full)
❌
JSON + polymorphic discriminators + toJsonLean
✅
✅ (no toJsonLean)
Sealed unions
✅ sealed $$Base + Dart 3 pattern matching
✅ via when/map helpers
Nested patch system (partial updates of deep graphs)
Where freezed differs (honest notes): freezed's mixin pattern
(with _$Foo) keeps the annotated class itself concrete; zorphy uses
abstract class $Foo + generated Foo. freezed's when/map helpers
are answered in zorphy by Dart 3's native exhaustive switch on the
sealed base. Freezed's ecosystem is older and larger.
It converts simple classes, sealed unions, @Default, @JsonKey, and
fromJson/toJson automatically, and reports anything that needs human
attention with file:line — nothing is silently dropped. See the
migration guide.
@Zorphy()
abstractclass $TodoList{
Stringget title;
List<Todo> get todos;
}
// Update specific item in listfinal patch = TodoListPatch.create()
..updateTodosAt(0, (todoPatch) => todoPatch
..withCompleted(true)
..withTitle('Updated Title'));
Functional Patches
// Using functions for computed updatesfinal patch = CounterPatch.create()
..withValue((current) => current + 1);
final updated = counter.patchWithCounter(patchInput: patch);
@Zorphy()
abstractclass $$Base<T> {
T get value;
}
@Zorphy()
abstractclass $Derived<Textendsnum> implements $$Base<T> {
@override
T get value;
T get doubled => value * 2;
}
6. Explicit Subtypes & ChangeTo
Use explicitSubTypes to enable cross-type operations:
@Zorphy()
abstractclass $User{
Stringget name;
String? get email;
String? get phone;
}
final user = User(name: 'Alice');
// email and phone are nullfinal withEmail = user.copyWith(email: 'alice@example.com');
14. Complex Nested Structures
@Zorphy()
abstractclass $Company{
Stringget name;
List<Department> get departments;
}
@Zorphy()
abstractclass $Department{
Stringget name;
List<Employee> get employees;
}
@Zorphy()
abstractclass $Employee{
Stringget name;
String? get title;
}
// Deep nesting with proper JSON supportfinal company = Company(
name: 'Tech Corp',
departments: [
Department(
name: 'Engineering',
employees: [
Employee(name: 'Alice', title: 'Engineer'),
],
),
],
);
15. Generic Fields and Methods
typedefJsonConverter<T> = T Function(dynamic);
@Zorphy()
abstractclass $ApiResponse<T> {
boolget success;
T? get data;
String? get error;
}
@Zorphy()
abstractclass $UserListResponseimplements $ApiResponse<List<User>> {
@overrideboolget success;
@overrideList<User>? get data;
@overrideString? get error;
}
# Build once
dart run build_runner build
# Build and watch for changes
dart run build_runner watch
# Clean generated files
dart run build_runner clean
# Or use the CLI
zorphy build
zorphy build --watch
zorphy build --clean
📝 Naming Conventions
Class Prefixes
$ClassName - Concrete class definition (use ClassName in code)
$$ClassName - Sealed abstract class (exhaustiveness checking)
$ClassName_ - Class with hidden private constructor
Generated Files
*.zorphy.dart - Generated code from @Zorphy annotation
Generated Enums
ClassName$ - Enum of field names for patch system
Generated Patch Classes
ClassNamePatch - Patch class for partial updates
🔄 Migration from Morphy
Zorphy is designed for easy migration from Morphy:
Replace @Morphy with @Zorphy
Replace morphy_annotation dependency with zorphy_annotation
Replace zikzak_morphy dependency with zorphy
Run dart run build_runner clean
Run dart run build_runner build
Key Differences:
Better patch system with nested support
Enhanced generic handling
Improved error messages
More flexible inheritance patterns
Built-in CLI and MCP server for AI agents
🐛 Troubleshooting
Type Not Found Errors
If you get type not found errors, ensure:
You've added part 'filename.zorphy.dart'; to your file
You've run dart run build_runner build or zorphy build
The import includes package:zorphy_annotation/zorphy_annotation.dart
Generic Type Issues
When using generics, ensure type parameter names match between parent and child:
Note:@Zorphy2 is deprecated in v2. The single-pass v2 generator handles ordering automatically — you no longer need to annotate build-order dependencies manually.
If you are migrating from v1 code that uses @Zorphy2, simply replace all @Zorphy2() annotations with @Zorphy() — the v2 generator will resolve the correct build order.
License
MIT License - see LICENSE file for details
Acknowledgments
Inspired by and designed to improve upon the Morphy code generation package.
Made with 🔥 by the ZikZak AI team for the community and AI agents