JSON to Dart Converter
Generate Flutter-ready Dart model classes from a JSON sample. Each object becomes a class with final typed fields, a named constructor ({required this.field}), a fromJson factory, and a toJson method — the serialization pair Flutter apps rely on. Nested objects and lists of objects are promoted to their own classes with the fromJson wiring already in place, so you can paste the output straight into a models/ directory.
How to use the JSON to Dart Converter
Paste a JSON object that represents one record — an API resource, a Firestore document, a config entry — and set the Root class name to match the model (for example User or Post). Click Generate. You get a complete Dart file: the root class plus a class for every nested object and every object found inside a list.
Each generated class has four parts. The fields are declared final with an inferred type (int, double, String, bool, List<T>, a nested class, or dynamic when the value is null or empty). The constructor is named and uses {required this.field} so every field must be supplied. The fromJson factory reads each value out of a Map<String, dynamic>, recursing into nested classes and mapping lists with .map(...).toList(). The toJson method rebuilds the map, calling toJson() on nested models. Use Copy to take the result, or Example to load a sample with nesting and a list of objects so you can see the full wiring.
Dart models, fromJson/toJson, and null safety
Dart has no reflection-based JSON binding in its core libraries, so the idiomatic pattern in Flutter is to hand-write (or generate) a model class with a fromJson factory and a matching toJson method. fromJson takes the Map<String, dynamic> that jsonDecode returns and constructs a typed object; toJson does the reverse so the model can be sent back over the wire or written to storage. This explicit pair is what packages like json_serializable ultimately produce, and writing it from a real payload is exactly what this tool automates.
Type inference maps JSON scalars to Dart's types: whole numbers become int, fractional numbers become double, strings become String, and booleans become bool. A JSON array becomes List<T> where T is the element type, and an array of objects yields a dedicated element class plus a .map((e) => ElementClass.fromJson(e)).toList() in the parent's fromJson. When a value is null or a collection is empty there is nothing to infer a type from, so the field falls back to dynamic — the one type that sidesteps Dart's sound null safety.
Because Dart enables sound null safety by default, the generated fields are non-nullable and the constructor marks them required; the safest behaviour for a generator working from a single sample is to assume every sampled field is present. If your API returns fields that are sometimes absent, change the relevant type to T? and relax the constructor by hand. For a TypeScript counterpart that performs the same structural inference but emits interfaces, see JSON to TypeScript.
Common use cases
- Flutter API clients — turn a REST or GraphQL response into typed models with serialization in one step.
- Firestore documents — model a document snapshot as a class so reads and writes share one shape.
- Local persistence — generate
toJson/fromJsonfor objects you cache in shared preferences or a JSON file. - Replacing build_runner boilerplate — get a quick model without wiring up
json_serializableand code generation. - Nested payloads — flatten a deeply nested response into a clean set of interrelated Dart classes.
- Prototyping — paste an unfamiliar payload to instantly scaffold the data layer for a new screen.
Frequently asked questions
Why are fields final and required?
final fields with a required constructor are the safest assumption when generating from one sample. If a field can be absent, change its type to T? and drop required.How does it choose int versus double?
int and a number with a decimal part becomes double. JSON has only one number type, so the choice is inferred from your example. Switch a field to num if it can be either.What happens with nested objects and lists of objects?
fromJson recurses into them and maps lists with .map((e) => Element.fromJson(e)).toList().Why is a field typed dynamic?
null value or an empty array gives nothing to infer from, so the field falls back to dynamic. Provide a non-null example value to get a concrete type.Do I still need json_serializable?
fromJson/toJson are plain Dart and need no build step. json_serializable remains useful for large schemas where you want generation tied into your build, but for a quick model this output is self-contained.