How JSON to Dart conversion actually works
When your Flutter app talks to a backend, the backend sends data as JSON. JSON is easy for the server to produce but awkward for a strongly typed language like Dart to consume — you cannot write user.name against a raw Map<String, dynamic> without losing the compiler's help. Converting JSON into a Dart class gives you real types, autocomplete, and compile-time checks.
Each class needs two methods: fromJson (takes a Map and produces an instance) and toJson (takes an instance and produces a Map). Writing these by hand for a single model is manageable. For an app with 15 models, most of which have nested objects and lists, it becomes a multi-hour chore where a single missed null check causes a runtime crash in production.
This tool does that conversion for you — with correct null safety, nested class generation, and list handling — in one click.
How this tool helps Flutter beginners
The problem with hand-writing models
You have to write the class, declare each field with the right type, write the constructor, write fromJson for every field (with type casts and null checks), write toJson, and handle nested objects and lists manually. The first time you forget to null-check a field, or you cast as String when the API sometimes returns an int, you get a TypeError at runtime — usually the worst possible time.
What this tool generates for you
Paste the JSON sample, click Convert, and you get a complete Dart file with typed fields, a constructor with required for non-nullable fields, a fromJson factory that handles nulls and type coercion safely, a toJson method that round-trips correctly, and separate classes for every nested object and list item. The generated code compiles under Dart 3 sound null safety.
Nested objects and lists
This is where hand-written code breaks most often. Take this sample:
{
"id": 1,
"name": "Alice",
"profile": {
"age": 28,
"city": "Berlin"
},
"orders": [
{ "id": "o_1", "total": 49.99 }
]
}
The generated Dart file contains three classes:
User— the root, with typed fields forid,name,profile(typed asUserProfile), andorders(typed asList<UserOrder>).UserProfile— the nested object, withageandcity.UserOrder— the list item, withidandtotal.
Each class has its own fromJson/toJson, and the parent's fromJson correctly calls UserProfile.fromJson on the nested map and UserOrder.fromJson on each element of the list.
Common mistakes when writing models by hand
- Casting to
Stringwhen the API sometimes returnsint. JSON does not distinguish types the way Dart does — a field that is usually"42"can occasionally be42if the backend serialises it inconsistently. This tool casts integers and doubles throughnumso the parse never throws. - Forgetting
requiredon non-nullable constructor params. Withoutrequired, Dart rejects the constructor when a non-nullable field is present. The generated constructor includesrequiredexactly where it is needed. - Marking every field nullable to "be safe". This defeats the point of typed models. Nullable marks should reflect fields the API can actually return as
null. Use a sample with real values to determine which fields are optional. - Not handling nested
toJson. A common bug is writingreturn { 'profile': profile }whereprofileis a class instance — Dart will throw when it tries to JSON-encode a non-primitive. This tool emitsprofile?.toJson()andorders.map((e) => e.toJson()).toList()automatically. - Forgetting to regenerate when the API changes. When a new field appears in the API, the hand-written model silently drops it during
fromJson. Regenerate whenever your sample JSON changes — it takes 3 seconds with this tool.
Using the generated file in your Flutter project
Save the generated code as lib/models/user.dart (or wherever your project keeps models). Then in your repository or service layer, parse the response:
import 'dart:convert';
import 'models/user.dart';
Future<User> fetchUser(String url) async {
final response = await http.get(Uri.parse(url));
final json = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(json);
}
For lists, User.listFromJson(jsonDecode(response.body) as List) would work if you generate a list at the root — this tool includes that pattern when your root is an array.
When to use json_serializable instead
This tool has an option to add json_serializable annotations. That is the right choice when your models have custom types (dates, enums, value objects) that you want to annotate with @JsonKey(fromJson:, toJson:) or custom JsonConverter classes. The generated code becomes much shorter — fromJson and toJson delegate to _$UserFromJson and _$UserToJson, and you run flutter pub run build_runner build to produce the actual logic.
If you do not want to add a build step, leave the checkbox off — you get a fully self-contained file that compiles without any dependency on json_serializable.
Things this tool does not do
- Detect
DateTimefields. Dates arrive as Strings or epoch integers. After generating, change the field type and updatefromJsontoDateTime.parse(...). - Detect enums. A string like
"active"is generated asString. If your API has a fixed set of values, replace it with an enum and add a small helper for parsing. - Infer types from a sample where every value is null. If a field is
nullin your sample, the tool usesdynamic. Paste a sample with a real value, or type the field manually after generating. - Handle
Map<String, dynamic>as a field. Dictionary-shaped fields generate asdynamic. Cast them manually if you know the value type.