PackageTrack
Sign in Get early access

dart_mappable

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

4.8.0 450K downloads/mo #547 most downloaded on pub.dev schultek/dart_mappable

What this package is like to depend on

Last release 4 months ago

20 Apr 2026

Release timing varies

gaps range from 9 days to 7 months

Most releases are documented

notes for 79 of 97 stable releases

Nothing withdrawn

no release was ever pulled

5 years old

127 releases · first in 2021

3 releases in the last 12 months

see the full history below

Release timeline

127 releases · Apr 2021 to Apr 2026
2022 2023 2024 2025 2026
Release Pre-release

Releases

latest 60 of 127
  1. 4.8.0 20 Apr 2026
    Release notes
    • Bump analyzer to >=10.0.0 <12.0.0.
    Open source →
  2. 4.7.0 08 Mar 2026
    Release notes
    • Added firstWhere to ListCopyWith for chaining copyWith calls on a list element based on a predicate function.
    • Add useNodoc option for excluding generated classes from dartdoc output.
    Open source →
  3. 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.
    Open source →
  4. 4.6.0 02 Aug 2025
    Release notes
    • Add 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 →
  5. 4.5.0 13 Mar 2025
    Release notes
    • Added shallowEncoding option to @MappableClass().
    • Added includeTypeId option to @MappableClass().
    Open source →
  6. 4.4.0 16 Feb 2025
    Release notes
    • Require sdk: >=3.6.0.
    Open source →
  7. 4.3.1 07 Feb 2025
    Release notes
    • Added MapperContainer.typeIdKey to support changing the '__type' key.
    Open source →
  8. 4.3.0 19 Oct 2024
    Release notes
    • Added support for reusing annotations as constant variables.
    • Added SimpleMapper1Bounded and SimpleMapper2Bounded for custom bounded generic types.
    • Fixed generation for generic functions.
    • Fixed bug with nullable generic field.
    • Fixed bug with import path on windows.
    Open source →
  9. 4.2.2 02 Apr 2024
    Release notes
    • Added CaseStyle.upperSnakeCase.
    • Fixed issues with adding unnecessary '__type' property for nullable generics.
    • Improved serialization consistency and equality handling.
    Open source →
  10. 4.2.1 01 Mar 2024
    Release notes
    • Performance improvements.
    • Updated docs.
    Open source →
  11. 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 →
  12. 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 →
  13. 4.0.1 21 Oct 2023
    Release notes
    • Added support for generic typed parameters for deep copyWith.
    Open source →
  14. 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 →
  15. 4.0.0-dev.1 19 Sep 2023 pre-release

    Nothing published for this version

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

    Nothing published for this version

  17. 3.3.1 11 Oct 2023
    Release notes
    • Improved migration docs regarding json_serializable and the difference of toJson().
    Open source →
  18. 3.3.0 08 Oct 2023
    Release notes
    • Make DateTime encoding configurable through DateTimeMapper.encodingMode.
    Open source →
  19. 3.2.0 01 Sep 2023
    Release notes
    • Handle bounded nested type parameters in subclasses.
    Open source →
  20. 3.1.3 08 Aug 2023
    Release notes
    • Fixed set equality.
    Open source →
  21. 3.1.2 11 Jul 2023
    Release notes
    • Fixed unexpected type error when decoding null.
    Open source →
  22. 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 →
  23. 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 →
  24. 3.0.1 19 May 2023
    Release notes
    • Fixed dependency conflict with package:collection.
    • Added topics for pub.dev.
    Open source →
  25. 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 →
  26. 3.0.0-dev.5 05 May 2023 pre-release

    Nothing published for this version

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

    Nothing published for this version

  28. 3.0.0-dev.3 15 Apr 2023 pre-release

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

  32. 2.0.3 16 Feb 2023
    Release notes
    • Fixed typo in readme (by @timmaffett)
    • Fixed generated container for private libraries.
    Open source →
  33. 2.0.2 01 Feb 2023
    Release notes
    • Fixed yet another unresolved type bug.
    Open source →
  34. 2.0.1 14 Jan 2023
    Release notes
    • Fixed unresolved type bug with custom mappers.
    Open source →
  35. 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 →
  36. 2.0.0-dev.13 10 Jan 2023 pre-release

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

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

    Nothing published for this version

  50. 1.2.0 08 Jun 2022
    Release notes
    • Added support for 2.17 super parameters
    Open source →
  51. 1.1.2 03 May 2022
    Release notes
    • Improved Readme for constructor utilization
    • Fixed missing imports for custom hooks
    Open source →
  52. 1.1.1 26 Apr 2022
    Release notes
    • Updated description
    Open source →
  53. 1.1.0 11 Apr 2022
    Release notes
    • Added support for custom enum values
      • Choose between ValuesMode.named and ValuesMode.indexed for automatic generation of encoded values
      • Use @MappableValue(myCustomValue) on an enum value to specify a custom encoded value
      • Deprecated the String toStringValue() extension method in favor of the more general dynamic toValue()
    Open source →
  54. 1.0.3 06 Apr 2022
    Release notes
    • Fixed issue with minified standard types on web
    Open source →
  55. 1.0.2 29 Mar 2022
    Release notes
    • Fixed unrecognized type issue for equals, hashCode and toString methods
    Open source →
  56. 1.0.1 29 Mar 2022
    Release notes
    • Improved resolving of constructor parameters, which fixed various issues in copyWith and toMap methods
    • Now printing comprehensive warning in the builder output if a parameter cannot be resolved
    Open source →
  57. 1.0.0 28 Mar 2022
    Release notes
    • Large refactoring and restructuring

      • Restructured builder implementation
      • Moved code out of generated files into package
      • Split package int dart_mappable and dart_mappable_builder
    • Mapper is now a singleton class

      • fromValue, toValue and all other methods are now instance methods accessible with Mapper.i.fromValue()
      • the legacy static methods are still available, but forward to the instance methods
    • Improved Readme, added How to use section and documented copyWith functionalities

    • Added @MappableLib() annotation and moved library-level configuration logic from build options to annotation properties

    • Switched to using the type_plus package for internal handling of generics

    • Added ChainedHooks, UnescapeNewlinesHooks and EmptyToNullHooks

    • Added descriptive and comprehensible exception handling

    Open source →
  58. 1.0.0+1 28 Mar 2022

    Nothing published for this version

  59. 1.0.0+2 28 Mar 2022

    Nothing published for this version

  60. 1.0.0-dev.7 28 Mar 2022 pre-release

    Nothing published for this version

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