Freezed + json_serializable Together: Flutter Example Guide
Freezed and json_serializable together in Flutter: setup, codegen, custom converters, and unions — a side-by-side example to help you pick the right one.
Every Flutter app talks to an API, and every API returns JSON. Somewhere in your codebase, JSON maps become Dart objects — and how you write that conversion code determines whether adding a field takes ten seconds or an afternoon of hunting down a typo. This guide shows freezed and json_serializable together in a Flutter example project: the two standard codegen approaches, side by side with the same model, so you can pick the right one — or confidently combine them. Why hand-written fromJson doesn't scale A hand-written model looks fine for three fields: class User { final String id; final String name; final String? avatarUrl; const User({required this.id, required this.name, this.avatarUrl}); factory User.fromJson(Map<String, dynamic> json) { return User( id: json['id'] as String, name: json['name'] as String, avatarUrl: json['avatar_url'] as String?, ); } Map<String, dynamic> toJson() => { 'id': id, 'name': name, 'avatar_url': avatarUrl, }; } Now multiply this by twenty models with nested objects, renamed keys, and date formats. Every field is a chance to mistype a key, forget a cast, or handle a null wrong — and the compiler can't help you because it's all stringly-typed maps. Code generation eliminates the boring, error-prone parts: you declare the shape, the generator writes the conversion. Step 1 — Set up the dependencies Both approaches need build_runner (the code generator runner) in dev_dependencies . Add to your pubspec.yaml : dependencies: json_annotation: ^4.9.0 freezed_annotation: ^2.4.0 dev_dependencies: build_runner: ^2.4.0 json_serializable: ^6.8.0 freezed: ^2.5.0 Then fetch packages: dart pub get # or: flutter pub get A build.yaml is optional — both generators work with defaults. If you want global options (like always serializing nested objects…