PackageTrack
Sign in Get early access

dart_mappable_builder

Improved json serialization and data classes with full support for generics, inheritance, customization and more.

4.9.0 76K downloads/mo #1246 most downloaded on pub.dev schultek/dart_mappable

What this package is like to depend on

Last release 3 months ago

26 May 2026

Release timing varies

gaps range from 2 weeks to 7 months

Nearly every release is documented

notes for 40 of 44 stable releases

Nothing withdrawn

no release was ever pulled

4 years old

66 releases · first in 2022

7 releases in the last 12 months

see the full history below

Release timeline

66 releases · Mar 2022 to May 2026
2023 2024 2025 2026
Release Pre-release

Releases

latest 60 of 66
  1. 4.9.0 26 May 2026
    Release notes
    • Bump analyzer to >=13.0.0 <14.0.0
    Open source →
  2. 4.8.0 20 Apr 2026
    Release notes
    • Bump analyzer to >=10.0.0 <13.0.0.

    4.7.0

    • Allow analyzer 10.0.0.
    • Add useNodoc option for excluding generated classes from dartdoc output.
    • Fix type signature of nested copyWith parameters in some cases.
    Open source →
  3. 4.7.0 08 Mar 2026

    Nothing published for this version

  4. 4.6.4 28 Jan 2026
    Release notes
    • Fix nested copyWith on a inherited class with the superclass and field type in another library.
    • Fix default value of a field not being prefixed correctly when set to a static constant.
    • Add ignore for invalid_use_of_protected_member warning in generated code.
    Open source →
  5. 4.6.3 08 Dec 2025
    Release notes
    • Added support for annotated enum typedefs.
    Open source →
  6. 4.6.2 07 Dec 2025
    Release notes
    • Allow analyzer 9.0.0.
    Open source →
  7. 4.6.1 10 Sep 2025
    Release notes
    • Record mappers now correctly uses hooks specified on the @MappableRecord annotation.
    • Nested records are now correctly initialized, and record mappers are included in the generated initializeMappers() method.
    • Getters are no longer falsely used in equality or stringify methods.
    • Bump analyzerto ^8.0.0, and build and source_gen to ^4.0.0.
    Open source →
  8. 4.6.0 02 Aug 2025
    Release notes
    • Migrate to new element2 analyzer model. Bump analyzer to >=7.5.9, build to 3.0.0 and source_gen to 3.0.0.
    • Added support for self-referencing generics (e.g. T extends Comparable<T>)
    • Fix handling of nullable function fields.
    • Disable formatting of generated files through // dart format off.
    • Require sdk: >=3.7.0.
    Open source →
  9. 4.5.0 13 Mar 2025
    Release notes
    • Added support for shallowEncoding and includeTypeId options of @MappableClass().
    • Fixed escaping of enum values.
    • Fixed copyWith method for unbounded and nullable-bounded generic types.
    • Fixed bug when using top-level variables as hooks.
    Open source →
  10. 4.4.0 16 Feb 2025
    Release notes
    • Update analyzer to >=7.0.0 <8.0.0 and source_gen to ^2.0.0. Bump other dependencies accordingly.
    • Require sdk: >=3.6.0.
    Open source →
  11. 4.3.1 04 Feb 2025
    Release notes
    • Fixed bug with bounded generic deep copyWith parameters.
    Open source →
  12. 4.3.1+1 07 Feb 2025

    Nothing published for this version

  13. 4.3.0 19 Oct 2024
    Release notes
    • Added support for reusing annotations as constant variables.
    • Fixed generation for generic functions.
    • Fixed bug with nullable generic field.
    • Fixed bug with import path on windows.
    Open source →
  14. 4.2.3 05 Apr 2024
    Release notes
    • Added lint ignores for 'override_on_non_overriding_member'.
    Open source →
  15. 4.2.2 02 Apr 2024
    Release notes
    • Fixed issues with adding unnecessary '__type' property for nullable generics.
    • Improved serialization consistency and equality handling.
    Open source →
  16. 4.2.1 01 Mar 2024
    Release notes
    • Performance improvements.
    Open source →
  17. 4.2.0 25 Dec 2023
    Release notes
    • Added custom typedef for mapping fields to resolve naming conflict.
    • Deprecated creating and linking custom MapperContainers. If you are affected by this see https://github.com/schultek/dart_mappable/issues/159.
    Open source →
  18. 4.1.0 06 Dec 2023
    Release notes
    • Added support for shallow encoding a class:
      • MyClassMapper.ensureInitialized().encodeMap<MyClass>(myClass, EncodingOptions(shallow: true))
    • Correctly escape $ in class names.
    • Added option to use unordered list equality with iterables:
      • IterableMapper.equalityMode = IterableEqualityMode.unordered
    • Added build_extensions option to builder configuration.
    Open source →
  19. 4.0.1 21 Oct 2023
    Release notes
    • Added support for generic typed parameters for deep copyWith.
    • Added lint ignores for 'unnecessary_cast', 'strict_raw_type' and 'inference_failure_on_untyped_parameter'.
    Open source →
  20. 4.0.0 12 Oct 2023
    Release notes

    Changelog

    • Require sdk: >=3.0.0.

    • Added support for Records.

      • Fields of a class can now be any record type.

      • You can annotate toplevel record typedefs:

          @MappableRecord()
          typedef Coordinates = ({double latitude, double longitude});

    Documentation

    Record Fields

    dart_mappable supports record fields out of the box.
    When you define a class, any field using a record type will be automatically included in the serialization.

    @MappableClass()
    class Location with LocationMappable {
      
      const Location({
        required this.name,
        required this.coordinates, 
      });
    
      final (String, String) name;
      final ({double lat, double lng}) coordinates;
    }

    An instance of this class would be encoded to:

    {
      "name": {
        "$1": "John",
        "$2": "Doe"
      },
      "coordinates": {
        "lat": 123,
        "lng": 456
      }
    }

    Record Aliases

    Additionally, you can create record type aliases using annotated typedefs:

    @MappableRecord()
    typedef Coordinates = ({double lat, double lng});

    When using this type for a field of another class, it will be serialized as expected.

    This also allows you to serialize records using the standalone generated mapper class as well as the generated extension methods:

    void main() {
      // Using the generated mapper class.
      Coordinates coords  = CoordinatesMapper.fromJson('{"lat": 123, "lng": 456}');
      
      // Using the generated extension methods.
      String json = coords.toJson();
    }

    Renaming Record Properties

    You can also annotate individual fields of a record alias to change the key or add a hook:

    @MappableRecord()
    typedef FullName = (@MappableField(key: 'firstName') String, @MappableField(hook: MyHook()) String);

    This will only work on annotated record type aliases, not inline record fields.

    Note: Since typedefs are just an alias for a type, you cannot define two aliases for the same type
    with different @MappableField() modifiers. Only one will be used for serialization.

    Open source →
    Release notes
    • Require sdk: >=3.0.0.

    • Added support for Records.

      • Fields of a class can now be any record type.

      • You can annotate toplevel record typedefs:

          @MappableRecord()
          typedef Coordinates = ({double latitude, double longitude});
        

      For a more detailed usage see the documentation.

    Open source →
  21. 4.0.0-dev.2 19 Sep 2023 pre-release

    Nothing published for this version

  22. 4.0.0-dev.1 19 Sep 2023 pre-release

    Nothing published for this version

  23. 4.0.0-dev.0 09 Jul 2023 pre-release

    Nothing published for this version

  24. 3.3.0 08 Oct 2023
    Release notes
    • Make enum encoding explicitly typed.
    • Update analyzer to '>=5.11.0 <7.0.0'
    Open source →
  25. 3.2.3 19 Sep 2023
    Release notes
    • Respect keys and hooks for annotated getters.
    Open source →
  26. 3.2.2 18 Sep 2023
    Release notes
    • Handle even more cases for generic subclassing.
    Open source →
  27. 3.2.1 01 Sep 2023
    Release notes
    • Handle bounded nested type parameters in subclasses.
    Open source →
  28. 3.2.0 09 Aug 2023
    Release notes
    • Added support for annotating getters with @MappableField, which will then be included in the encoding, equality checks, and stringification of that class.
    Open source →
  29. 3.1.2 28 Jul 2023
    Release notes
    • Fixed bug with broken mapper generation.
    Open source →
  30. 3.1.1 09 Jun 2023
    Release notes

    Changelog

    • The builder now respects basic initializer expressions of a constructor. This makes it
      possible to do field renaming or assigning to private fields without requiring an additional
      getter matching the parameter.

      The following is now supported out of the box:

      class MyClass {
        MyClass(int value, {String? name}) 
            // Effectively renaming 'value' to 'data'.
          : data = value,
            // Assigning to a private field + having a null fallback.
            _name = name ?? 'Unnamed';
      
        final int value;
        final String _name;
    • Fixed encoding of a map now returns a Map<String, dynamic> where possible
      (instead of a Map<dynamic, dynamic>)

    • Fixed supporting expressions in @MappableClass.includeCustomMappers.

    • Fixed error when using non-literal values in @MappableValue().

    • Fixed generic decoding when using generic superclass.

    • Fixed unknown-type bug for serialized non-constructor fields.

    • Fixed bug with undetermined includeSubClasses.

    Open source →
    Release notes
    • Fixed supporting expressions in @MappableClass.includeCustomMappers.
    Open source →
  31. 3.1.0 09 Jun 2023
    Release notes
    • Fixed error when using non-literal values in @MappableValue().

    • The builder now respects basic initializer expressions of a constructor. This makes it possible to do field renaming or assigning to private fields without requiring an additional getter matching the parameter.

      The following is now supported out of the box:

      class MyClass {
        MyClass(int value, {String? name}) 
            // Effectively renaming 'value' to 'data'.
          : data = value,
            // Assigning to a private field + having a null fallback.
            _name = name ?? 'Unnamed';
      
        final int value;
        final String _name;
      
    • Fixed encoding of a map now returns a Map<String, dynamic> where possible (instead of a Map<dynamic, dynamic>)

    Open source →
  32. 3.0.2 15 May 2023
    Release notes
    • Fixed generic decoding when using generic superclass.
    • Fixed unknown-type bug for serialized non-constructor fields.
    Open source →
  33. 3.0.1 09 May 2023
    Release notes
    • Fixed bug with undetermined includeSubClasses.
    Open source →
  34. 3.0.0 08 May 2023
    Release notes

    Changelog

    • Breaking: Generated mappers no longer have a .container property. This was removed in favor
      of the new MapperContainer.globals container.

      // Instead of this:
      var value = MyClassMapper.container.fromValue(...);
      // Do this:
      var value = MapperContainer.globals.fromValue(...);

      Mapper initialization and usage is now simplified to the following:

      1. When used explicitly (e.g. through MyClassMapper.fromMap or myClass.toMap()) no additional
        initialization is needed.
      2. When used implicitly (through a generic type e.g. MapperContainer.globals.fromMap<MyClass>()) the
        mapper needs to be initialized once before being used with MyClassMapper.ensureInitialized().
    • Breaking: Changed internal mapper implementation which causes any custom mapper to break.

      • Removed MapperElementBase class.
      • Added MappingContext being passed to mapper methods.

      See docs on how to use custom mappers in v3.

    • Breaking: Removed @MappableLib.createCombinedContainer in favor of @MappableLib.generateInitializerForScope.

      Instead of generating a new container, v3 generates an initialization function for all mappers. Use it early on in your
      application:

      @MappableLib(generateInitializerForScope: InitializerScope.package)
      library main;
      
      import 'main.init.dart';
      
      void main() {
        initializeMappers();
        ...
      }
    • Breaking: Improved support and features for .copyWith.

      • Copy-With now supports classes that implement multiple interfaces.
      • Renamed .copyWith.apply() method to .copyWith.$update().
      • Added .copyWith.$merge() and .copyWith.$delta().

      You can now use .copyWith with either an existing instance using .$merge or a map of values using .$delta.

      @MappableClass()
      class A with AMappable {
        A(this.a, this.b);
        
        int? a;
        int? b;
      }
      
      void main() {
        var a = A(1, null);
        
        var c = a.copyWith.$merge(A(null, 2));
        assert(c == A(1, 2));
      
        var d = a.copyWith.$delta({'b': 2});
        assert(d == A(1, 2));
      }
    • Breaking: Removed CheckTypesHook in favor of discriminator functions.

      You can now use a custom predicate function as the discriminatorValue of a class. This function can check
      whether the encoded value should be decoded to this subclass and return a boolean.

      @MappableClass()
      abstract class A with AMappable {
        A();
      }
      
      @MappableClass(discriminatorValue: B.checkType)
      class B extends A with BMappable {
        B();
        
        /// checks if [value] should be decoded to [B]
        static bool checkType(value) {
          return value is Map && value['isB'] == true;
        }
      }
      
      @MappableClass(discriminatorValue: C.checkType)
      class C extends A with CMappable {
        C();
        
        /// checks if [value] should be decoded to [C]
        static bool checkType(value) {
          return value is Map && value['isWhat'] == 'C';
        }
      }
    • Added support for serializing fields that are not part of the constructor
      when annotated with @MappableField().

    • Added EncodingOptions to toValue method.

    • Added support for third-party models by using annotated typedefs.

    • Added renameMethods to build options.

    • Improved performance of generated encoding and decoding methods.

    For a detailed migration guide, see this issue.

    Open source →
    Release notes
    • Breaking: Generated mappers no longer have a .container property. This was removed in favor of the new MapperContainer.globals container.

      // Instead of this:
      var value = MyClassMapper.container.fromValue(...);
      // Do this:
      var value = MapperContainer.globals.fromValue(...);
      

      Mapper initialization and usage is now simplified to the following:

      1. When used explicitly (e.g. through MyClassMapper.fromMap or myClass.toMap()) no additional initialization is needed.
      2. When used implicitly (through a generic type e.g. MapperContainer.globals.fromMap<MyClass>()) the mapper needs to be initialized once before being used with MyClassMapper.ensureInitialized().
    • Breaking: Changed internal mapper implementation which causes any custom mapper to break.

      • Removed MapperElementBase class.
      • Added MappingContext being passed to mapper methods.

      See docs on how to use custom mappers in v3.

    • Breaking: Removed @MappableLib.createCombinedContainer in favor of @MappableLib.generateInitializerForScope.

      Instead of generating a new container, v3 generates an initialization function for all mappers. Use it early on in your application:

      @MappableLib(generateInitializerForScope: InitializerScope.package)
      library main;
      
      import 'main.init.dart';
      
      void main() {
        initializeMappers();
        ...
      }
      
    • Breaking: Improved support and features for .copyWith.

      • Copy-With now supports classes that implement multiple interfaces.
      • Renamed .copyWith.apply() method to .copyWith.$update().
      • Added .copyWith.$merge() and .copyWith.$delta().

      You can now use .copyWith with either an existing instance using .$merge or a map of values using .$delta.

      @MappableClass()
      class A with AMappable {
        A(this.a, this.b);
        
        int? a;
        int? b;
      }
      
      void main() {
        var a = A(1, null);
        
        var c = a.copyWith.$merge(A(null, 2));
        assert(c == A(1, 2));
      
        var d = a.copyWith.$delta({'b': 2});
        assert(d == A(1, 2));
      }
      
    • Breaking: Removed CheckTypesHook in favor of discriminator functions.

      You can now use a custom predicate function as the discriminatorValue of a class. This function can check whether the encoded value should be decoded to this subclass and return a boolean.

      @MappableClass()
      abstract class A with AMappable {
        A();
      }
      
      @MappableClass(discriminatorValue: B.checkType)
      class B extends A with BMappable {
        B();
        
        /// checks if [value] should be decoded to [B]
        static bool checkType(value) {
          return value is Map && value['isB'] == true;
        }
      }
      
      @MappableClass(discriminatorValue: C.checkType)
      class C extends A with CMappable {
        C();
        
        /// checks if [value] should be decoded to [C]
        static bool checkType(value) {
          return value is Map && value['isWhat'] == 'C';
        }
      }
      
    • Added support for serializing fields that are not part of the constructor when annotated with @MappableField().

    • Added EncodingOptions to toValue method.

    • Added support for third-party models by using annotated typedefs.

    • Added renameMethods to build options.

    • Improved performance of generated encoding and decoding methods.

    For a detailed migration guide, see this issue.

    Open source →
  35. 3.0.0-dev.5 05 May 2023 pre-release

    Nothing published for this version

  36. 3.0.0-dev.4 05 May 2023 pre-release

    Nothing published for this version

  37. 3.0.0-dev.2 13 Apr 2023 pre-release

    Nothing published for this version

  38. 3.0.0-dev.1 10 Mar 2023 pre-release

    Nothing published for this version

  39. 3.0.0-dev.0 25 Feb 2023 pre-release

    Nothing published for this version

  40. 2.0.2 24 Feb 2023
    Release notes
    • Fixed an analysis error when using core interfaces.
    Open source →
  41. 2.0.1 16 Feb 2023
    Release notes
    • Fixed generated container for private libraries.
    Open source →
  42. 2.0.0 11 Jan 2023
    Release notes
    • Mappers are now generated for each file containing annotated classes. This removes the
      need to specify entry points in the build.yaml.

      This is now similar to how packages like json_serializable or freezed generate code.

      • Generated files are now part files and need to be included as such.
      • All annotated classes must now use their respective <MyClass>Mappable mixin.
      • Instead of one global Mapper each class has its own <ClassName>Mapper.
        • A new global container that includes all models can now be generated using
          @MappableLib(createCombinedContainer: true).
      • Mappers can be linked together to enable working with multiple classes.
      • Removed @CustomMapper annotation in favor of includeCustomMappers property on @MappableClass().

      For a detailed migration guide, see this issue.

    • Documentation is now separated from the README using the official pub.dev documentation topics.
      Find the new documentation here

    • Improvements in performance and support for generics and inheritance.

    • Added the [CheckTypesHook] to allow for custom discriminator checks on subclasses in a
      polymorphic class structure.

    • CopyWith is now more powerful and also works for generic or polymorphic classes, while being
      completely type-safe.

      When called on a superclass, the concrete subtype will be retained through a
      .copyWith call, which also respects generics:

        // with `class A` and `class B<T> extends A`
        A a = B<int>(); // static type A, dynamic type B<int>
      
        // signature will be `A copyWith()`, so static type A
        A a2 = a.copyWith(); 
      
        // this will still resolve to a dynamic type of B<int>
        assert(a2 is B<int>);

      For more checkout the docs
      or example

    Open source →
    Release notes
    • Mappers are now generated for each file containing annotated classes. This removes the need to specify entry points in the build.yaml.

      This is now similar to how packages like json_serializable or freezed generate code.

      • Generated files are now part files and need to be included as such.
      • All annotated classes must now use their respective <MyClass>Mappable mixin.
      • Instead of one global Mapper each class has its own <ClassName>Mapper.
        • A new global container that includes all models can now be generated using @MappableLib(createCombinedContainer: true).
      • Mappers can be linked together to enable working with multiple classes.
      • Removed @CustomMapper annotation in favor of includeCustomMappers property on @MappableClass().

      For a detailed migration guide, see this issue.

    • Documentation is now separated from the README using the official pub.dev documentation topics. Find the new documentation here

    • Improvements in performance and support for generics and inheritance.

    • Added the [CheckTypesHook] to allow for custom discriminator checks on subclasses in a polymorphic class structure.

    • CopyWith is now more powerful and also works for generic or polymorphic classes, while being completely type-safe.

      When called on a superclass, the concrete subtype will be retained through a .copyWith call, which also respects generics:

        // with `class A` and `class B<T> extends A`
        A a = B<int>(); // static type A, dynamic type B<int>
      
        // signature will be `A copyWith()`, so static type A
        A a2 = a.copyWith(); 
      
        // this will still resolve to a dynamic type of B<int>
        assert(a2 is B<int>);
      

      For more checkout the docs or example

    Open source →
  43. 2.0.0-dev.13 10 Jan 2023 pre-release

    Nothing published for this version

  44. 2.0.0-dev.12 09 Jan 2023 pre-release

    Nothing published for this version

  45. 2.0.0-dev.11 05 Jan 2023 pre-release

    Nothing published for this version

  46. 2.0.0-dev.10 04 Jan 2023 pre-release

    Nothing published for this version

  47. 2.0.0-dev.9 04 Jan 2023 pre-release

    Nothing published for this version

  48. 2.0.0-dev.8 02 Jan 2023 pre-release

    Nothing published for this version

  49. 2.0.0-dev.7 02 Jan 2023 pre-release

    Nothing published for this version

  50. 2.0.0-dev.6 02 Dec 2022 pre-release

    Nothing published for this version

  51. 2.0.0-dev.5 28 Oct 2022 pre-release

    Nothing published for this version

  52. 2.0.0-dev.4 24 Oct 2022 pre-release

    Nothing published for this version

  53. 2.0.0-dev.3 24 Oct 2022 pre-release

    Nothing published for this version

  54. 2.0.0-dev.2 18 Oct 2022 pre-release

    Nothing published for this version

  55. 2.0.0-dev.1 15 Oct 2022 pre-release

    Nothing published for this version

  56. 2.0.0-dev.0 30 Sep 2022 pre-release

    Nothing published for this version

  57. 1.2.1 15 Nov 2022

    Nothing published for this version

  58. 1.2.0 08 Jun 2022
    Release notes
    • Added support for 2.17 super parameters
    Open source →
  59. 1.1.3 18 May 2022
    Release notes
    • Fixed import paths on windows
    Open source →
  60. 1.1.2 03 May 2022
    Release notes
    • Improved Readme for constructor utilization
    • Fixed missing imports for custom hooks
    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive