json_serializable with build_runner in Flutter: solved exercise
json_serializable with build_runner in Flutter: solved exercise
Writing fromJson and toJson by hand is repetitive and error-prone. json_serializable generates that code automatically from annotations, and is lighter than Freezed when you only need serialization without immutability or union types.
Problem statement
Create a User model with required and optional fields, serializable to/from JSON. Demonstrate:
- Fields with a different JSON name (
@JsonKey). - Optional fields with default values.
- Serialization of nested lists.
- Parsing a list of users from a JSON array.
Dependencies
Running build_runner
Solution: User model
Solution: list parsing helper
Full usage
Generated file: user_dto.g.dart
After the build you get something like this (do not edit it):
Common mistakes
- Forgetting
part 'user_dto.g.dart': the compiler cannot find_$UserDtoFromJsonand fails. - Renaming a field without updating
@JsonKey: the field is not deserialized and silently gets its default value. - Not adding
@JsonKey(defaultValue: ...)for optional fields: if the API omits the field,fromJsonthrowsNull check operator used on a null value.
json_serializable vs Freezed
| Need | json_serializable | Freezed |
|---|---|---|
| fromJson / toJson | ✅ | ✅ |
| Generated copyWith | ❌ | ✅ |
| Generated == and hashCode | ❌ | ✅ |
| Union types | ❌ | ✅ |
| Fewer dependencies | ✅ | ❌ |
Use json_serializable alone if you do not need deep immutability. For medium and large projects, Freezed is worth the extra setup.
Practical use
Any app consuming a JSON API benefits from this workflow: define the DTO, annotate, run build_runner, and get robust typed serialization with no manual code.
Recommended next exercise
- Freezed and json_serializable in Flutter: solved exercise
- DTO to domain mapper in Flutter: solved exercise
- Flutter API call with http: solved exercise
- All Flutter exercises
Guided practice and next step
- More Flutter exercises
- C exercises to strengthen fundamentals
- Programming in C in 100 Solved Exercises
- View the book on Amazon (included in Kindle Unlimited)
- Subscribe to the newsletter
FAQ
Does build_runner generate code for all annotated classes at once?
Yes. A single build_runner build processes all annotated files in the project. There is no native way to process a single file selectively.
Can I use explicitToJson: true for nested classes?
Yes. Add @JsonSerializable(explicitToJson: true) if you have nested objects that also have toJson; otherwise they serialize as raw Map<String, dynamic> without calling their own toJson.
Does it work with enums?
Yes. Add @JsonValue('json_value') to each enum entry and @JsonKey(unknownEnumValue: MyEnum.unknown) on the field to handle unexpected API values gracefully.