json_serializable: Automating JSON in Dart
json_serializable is a boilerplate-writing robot for Dart, automatically generating code to convert classes to and from JSON. It's essential for data models in network requests or local storage.
WHY IT EXISTS Manually writing JSON serialization code (fromJson, toJson) is repetitive, tedious, and a major source of bugs. A typo in a JSON key string can cause silent failures at runtime. This process needed to be automated to improve developer productivity and ensure code is correct and maintainable.
THE MENTAL MODEL Think of json_serializable as a contract with a code-generating assistant. You define the shape of your data in a Dart class and add special instructions (annotations). The assistant then reads your instructions and writes the perfect, corresponding serialization logic in a separate file for you to use. You never touch the generated code; you just re-run the assistant when your class changes.
HOW IT WORKS You add json_annotation as a dependency, and json_serializable plus build_runner as dev dependencies. First, you annotate a data class with @JsonSerializable. Second, you add a part 'my_file.g.dart'; directive at the top of your file. Third, you add the required hooks inside your class: a factory constructor factory YourClass.fromJson(Map<String, dynamic> json) => _YourClassFromJson(json); and a method Map<String, dynamic> toJson() => _YourClassToJson(this);. Finally, you run dart run build_runner build in your terminal. This command scans your project for annotations and generates the my_file.g.dart file containing the helper functions.
WHEN TO USE IT Use it for virtually any plain data object in a Flutter or Dart application that needs to interact with JSON. This is standard practice for models representing API responses, data sent to a server, or objects persisted in local storage. It's especially valuable for complex, nested objects and handles type conversions (like String to DateTime) automatically.
WHEN NOT TO USE IT For extremely simple, one-off cases with only one or two primitive fields, manual serialization might be faster than the initial build configuration setup. However, for any project of meaningful size, the setup cost pays for itself quickly. Avoid it if you have no control over the class you need to serialize (e.g., from a third-party package without its own support).
ONE CANONICAL EXAMPLE To make a Person class serializable, you annotate it and add the factory and method hooks: @JsonSerializable() class Person { final String firstName; final DateTime dateOfBirth; Person({required this.firstName, required this.dateOfBirth}); factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); Map<String, dynamic> toJson() => _$PersonToJson(this); } After running the build runner, the generator creates the _$PersonFromJson function, which correctly maps the firstName string and parses the dateOfBirth from its ISO 8601 string format into a DateTime object.
Read the original → pub.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.