Skip to content

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.

Style:

Generated code

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 null in the sample and a key that wasmissing from one element of a list both becomeT? in Dart — but only the missing one is skipped bytoJson when null, so a round-trip reproduces your input instead of inventing keys.
  • 1 and 1.0 are read from the raw token. JSON.parse would erase the difference; this tool's own reader keeps it, so a field that ever showed a decimal point becomes double, and integer fields stay int.
  • Dates are detected, strictly. A string field becomes DateTime only when every sample matches full ISO 8601 (2026-07-03,2026-07-03T10:30:00Z). One non-matching value demotes the field back to String. 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 int here and a4.5 there merge to double, and genuinely mixed types degrade to dynamic — 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 numdouble 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?

StyleBest forTrade-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_serializableTeams 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.99final double price; read via (… as num).toDouble().
  • "created-at" isn't a legal identifier → the field is createdAt, but fromJson/toJson still use the original 'created-at' key.
  • "note": nulldynamic, plus a warning that the sample never showed its type.
  • "rating" is 4.5 for one user and 5 for another → merged to double.
  • "last_login" is missing from the second user → DateTime?, and toJson omits the key when it's null.
  • "users": […]List<User> with a proper User.fromJson per 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.