1. Home
  2. Developer tools
  3. JSON to Dart Class

JSON to Dart Class

Generate null-safe Flutter model classes with working fromJson and toJson methods, without a build_runner step.

Free, no sign-up. Runs in your browser: nothing is uploaded.

How to use JSON to Dart Class

  1. Paste JSON.
  2. Name the root class.
  3. Copy the classes into lib/models.

Features

  • Null-safe final fields with required named parameters
  • fromJson factories that convert nested objects and lists
  • toJson that serialises nested objects back
  • Doubles read through num, so 5 and 5.0 both work
  • No code generation or extra packages

Supported formats

You can open

  • JSON
  • JSON Lines
  • Typed or pasted text

You get

  • DART
  • Copied text

Private by design

Your files are opened and processed by your browser on this device. They are never uploaded to openWorkstand or anyone else, so the JSON to Dart Class is safe for contracts, IDs, photos and work documents. After you have used it once while online, it also works without an internet connection. How local processing works

Good to know

  • Types are inferred from the samples given; paste several varied samples for accurate optional fields.

Guide

Flutter model classes with fromJson and toJson

Dart has no reflection in Flutter release builds, so JSON must be converted by explicit code: a factory that reads a map and a method that writes one. Writing those by hand for nested data is repetitive and easy to get subtly wrong. This generator writes complete, null-safe model classes from a sample, with working fromJson and toJson and no build step.

The shape of each class

Every object in the sample becomes a class with final fields and a const constructor using named parameters. Fields that had a value in every sample are non-nullable and required; fields that were missing or null somewhere are nullable and optional. Property names follow Dart’s camelCase, with the original key kept in the conversion code.

fromJson

The factory reads each key from a Map<String, dynamic> and converts it. Strings, integers and booleans are cast directly. Decimals are read as num and converted with toDouble(), because the decoder turns 5 into an int even when the field usually holds 5.5. Nested objects call the nested class’s fromJson, and lists are mapped item by item: (json['orders'] as List<dynamic>).map((e) => Order.fromJson(e as Map<String, dynamic>)).toList(). Nullable fields use null-aware versions of the same expressions.

toJson

Sending data back to an API needs the reverse. toJson writes every field under its original key, calls toJson() on nested objects and maps lists of objects, so jsonEncode(user) produces JSON with the same shape you started with.

No build_runner needed

Packages such as json_serializable generate the same code from annotations, which pays off for large apps with many changing models. Plain classes avoid the generator, the part files and the build step, and they are easy to read and debug. Start with these and move to code generation when the number of models grows.

A worked example

The sample user produces User, Order, Item and Address classes. In Order, the total is read as (json['total'] as num).toDouble(), the items as (json['items'] as List<dynamic>).map((e) => Item.fromJson(e as Map<String, dynamic>)).toList(), and toJson writes 'orders': orders.map((e) => e.toJson()).toList() in User.

Decoding in a Flutter app

Fetch with the http package, then User.fromJson(jsonDecode(response.body) as Map<String, dynamic>). For large responses, run the decoding in a background isolate with compute or Isolate.run so the interface does not stutter.

Refining the models

Replace string fields that hold fixed values with enums, add DateTime.parse for timestamps you want as dates, and consider equality with == and hashCode (or the equatable package) for models used in state management.

Handling errors while decoding

The casts in fromJson throw a TypeError when a value has an unexpected type, for example a string where an int was expected. Wrap decoding of external data in a try/catch at the point where the response arrives, log the raw body when it fails, and show a friendly message instead of a red error screen.

Root lists and pagination

When the response is a list, the root class describes one item; when it is wrapped with paging fields, the wrapper becomes the root class with a list of items inside, so page and total are typed as well.

Generate the native models with JSON to Kotlin and JSON to Swift, TypeScript for a web client with JSON to TypeScript, or tidy the sample in the JSON Formatter.

Checked against the current version of the JSON to Dart Class on .

Troubleshooting

The file does not open

Check that it is one of the supported formats above and opens in another app. Damaged files and password-protected PDFs cannot be read until they are repaired or unlocked.

It is slow or stops on a very large file

Everything runs on your device, so speed depends on its memory. Close other tabs, use a computer rather than a phone, or split the file into smaller parts first.

The download did not start

Look for your browser’s download bar or icon. Some browsers ask once before a site may download files; allow it and click the button again.

Frequently asked questions

Why does fromJson cast through num for decimals?

dart:convert decodes 5 as an int and 5.0 as a double. A field that is usually a decimal can arrive as a whole number, and casting it directly to double would throw; num accepts both and toDouble() converts.

Can I add copyWith and equality?

Yes, by hand or with a package. For many models, freezed generates copyWith, == and hashCode along with JSON code; for a few, writing copyWith by hand is quick because the fields are already listed.

Where should these files live?

A common layout is lib/models/ with one file per root model, exported from a models.dart barrel file so screens import them in one line.

Should I use json_serializable instead?

For large models that change often, json_serializable with build_runner saves maintenance. For a handful of models, plain classes like these avoid the code-generation step and are easy to read.

How do I decode a list response?

Decode with jsonDecode, cast to List<dynamic>, and map each item: (jsonDecode(body) as List<dynamic>).map((e) => Item.fromJson(e as Map<String, dynamic>)).toList().

Keep working with the result

openWorkstand also includes a free workspace with documents, spreadsheets, tasks, projects and a calendar that save to a folder on your computer.