Tools
JSON to Dart
Paste JSON, get null-safe Dart model classes withfromJson and toJson — nullability, optional fields, doubles and dates inferred honestly from your sample. Runs entirely in your browser.
Generated code
More on this site: all tools ·JSON formatter ·regex checker ·the arcade
Beta — the generated code is unit- and compile-tested, but inference from one sample can't be perfect; on rare occasions the output may need a tweak. Spot something wrong?Tell me.
What is this tool?
A free JSON-to-Dart converter. Paste a JSON document — an API response, a config file, a Firestore export — and it generates idiomatic, null-safe Dart classes ready to drop into a Flutter or server-side Dart project: finalfields, a const constructor withrequired parameters, a fromJson factory and a toJson method that round-trips your original keys exactly. Output regenerates live as you type.
Your JSON never leaves the browser. Parsing, inference and code generation are pure client-side code — the page works offline once loaded. That matters, because the JSON people convert is usually a real response from a private API.
How to use it
- Paste JSON on the left — the Dart appears on the right as you type.
- Name the root class (defaults to
Response); nested classes are named from their keys, singularized inside lists (users: […]→User). - Pick a style: plain classes (zero dependencies) or json_serializable annotations for teams already running build_runner.
- Check the warnings panel: every place your sample was too thin to type (an empty array, an always-null field) is called out by its JSON path instead of guessed silently.
- Copy or Download the file, named after the root class (
response.dart).
What the inference gets right
- Nullable vs optional are different things. A key whose value was
nullin the sample and a key that wasmissing from one element of a list both becomeT?in Dart — but only the missing one is skipped bytoJsonwhen null, so a round-trip reproduces your input instead of inventing keys. 1and1.0are read from the raw token.JSON.parsewould erase the difference; this tool's own reader keeps it, so a field that ever showed a decimal point becomesdouble, and integer fields stayint.- Dates are detected, strictly. A string field becomes
DateTimeonly when every sample matches full ISO 8601 (2026-07-03,2026-07-03T10:30:00Z). One non-matching value demotes the field back toString. Toggle it off if you'd rather keep strings. - List elements are merged, not sampled. Every element of an array contributes: a field missing from one object becomes optional, an
inthere and a4.5there merge todouble, and genuinely mixed types degrade todynamic— with a warning naming the exact path. - Identical shapes become one class. Two objects with the same fields collapse into a single class (toggle it off if you expect them to diverge later).
Null safety done properly
Since Dart 2.12, types are non-nullable by default — and generated code should embrace that, not fight it. The classes here make every field the sample supports non-nullable andrequired; only fields that were null or missing getT?. There is no late, no!, and no nullable-everything cop-out: if your sample shows the data is always there, your code shouldn't have to null-check it forever. If you don't trust your sample, flip on All fields optional and every field becomes T? honestly.
The num → double pitfall
The #1 runtime crash from naive converters: a field typeddouble, cast as json['price'] as double. The moment the API returns a whole number — 5 instead of 4.5 — Dart decodes it as int, the cast throws, and the crash lands in production. Generated code here always reads double fields as:
price: (json['price'] as num).toDouble(),which accepts both. Integer fields keep the strictas int cast — if the API sends 1.5 where your sample said 1, that should fail loudly rather than silently truncate.
Plain classes or json_serializable?
| Style | Best for | Trade-off |
|---|---|---|
| Plain classes (default) | Most projects — zero dependencies, no codegen step, the whole class is readable in one screen. | Serialization logic lives in your source; edits to the shape mean editing two methods. |
| json_serializable | Teams already running build_runner — annotations only, the generated .g.dart part does the work. | Adds json_annotation + a build step; explicitToJson: true is included so nested models actually serialize (a classic gotcha). |
freezed-style output (immutable unions,copyWith) is planned — plain classes cover the paste-and-ship case it's usually reached for.
Worked example
Load the Sample and look at what comes back:
"price": 9.99→final double price;read via(… as num).toDouble()."created-at"isn't a legal identifier → the field iscreatedAt, butfromJson/toJsonstill use the original'created-at'key."note": null→dynamic, plus a warning that the sample never showed its type."rating"is4.5for one user and5for another → merged todouble."last_login"is missing from the second user →DateTime?, andtoJsonomits the key when it's null."users": […]→List<User>with a properUser.fromJsonper element.
FAQ
Is it free? Yes — free, no sign-up, no limits.
Is my JSON uploaded anywhere? No. Everything runs in your browser; the page works offline after loading. Your last input is kept in your own browser's local storage so it survives a reload — nothing else.
Why did a field come out dynamic?The sample didn't pin it down: the value was alwaysnull, the array was empty, or two samples disagreed (a string here, a number there). The warnings panel names the exact JSON path. Add one representative value and regenerate.
Why is a field nullable when my API always sends it?Because in this sample it was null or missing at least once. The tool can only be as sure as your sample — paste a richer one, or edit the generated field.
Can it read a JSON Schema or OpenAPI spec? Not yet — v1 infers from JSON samples. Schema input is planned.
Which Dart does the output target? Null-safe Dart — 2.12+ and Dart 3. No dependencies at all in plain-class style.
Built from scratch for this site in vanilla TypeScript — a pure, unit-tested inference engine (token-level number reading, a proper merge lattice, golden-tested emitters) and zero runtime dependencies.