JSON to Dart converter
Paste JSON, get null-safe Dart classes with fromJson and toJson: as plain Dart, json_serializable or Freezed. It runs in your browser, so your data never leaves the page.
Free · No sign-up · Updated 26 September 2026
Convert JSON to Dart
Runs in your browser. Nothing you paste is uploaded or stored. Up to 2,000,000 characters.
Dart
class User {
final int id;
final String firstName;
final String lastName;
final dynamic email;
final bool isActive;
final double rating;
final String joinedAt;
final List<String> roles;
final Settings settings;
const User({
required this.id,
required this.firstName,
required this.lastName,
this.email,
required this.isActive,
required this.rating,
required this.joinedAt,
required this.roles,
required this.settings,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
firstName: json['first_name'] as String,
lastName: json['last_name'] as String,
email: json['email'],
isActive: json['is_active'] as bool,
rating: (json['rating'] as num).toDouble(),
joinedAt: json['joined_at'] as String,
roles: (json['roles'] as List<dynamic>).map((e) => e as String).toList(),
settings: Settings.fromJson(json['settings'] as Map<String, dynamic>),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'first_name': firstName,
'last_name': lastName,
'email': email,
'is_active': isActive,
'rating': rating,
'joined_at': joinedAt,
'roles': roles,
'settings': settings.toJson(),
};
}
}
class Settings {
final String theme;
final Notifications notifications;
const Settings({
required this.theme,
required this.notifications,
});
factory Settings.fromJson(Map<String, dynamic> json) {
return Settings(
theme: json['theme'] as String,
notifications: Notifications.fromJson(json['notifications'] as Map<String, dynamic>),
);
}
Map<String, dynamic> toJson() {
return {
'theme': theme,
'notifications': notifications.toJson(),
};
}
}
class Notifications {
final bool email;
final bool push;
const Notifications({
required this.email,
required this.push,
});
factory Notifications.fromJson(Map<String, dynamic> json) {
return Notifications(
email: json['email'] as bool,
push: json['push'] as bool,
);
}
Map<String, dynamic> toJson() {
return {
'email': email,
'push': push,
};
}
}
3 classes.
Notes about this conversion (1)
- $.email is always null in the sample, so it is typed dynamic.
How the types are chosen
Read the way Dart will read it.
The converter follows the rules Dart's own JSON decoder uses, so a field is typed the way your app will actually receive it.
| In the JSON | In Dart | Notes |
|---|---|---|
| "text" | String | DateTime instead, if you turn on the date option and every value of that field is an ISO 8601 date. |
| 42 | int | Read with as int. |
| 42.5, 10.0, 1e3 | double | On the Dart VM (Flutter on mobile and desktop) a number written with a decimal point or an exponent decodes as a double, so 10.0 is a double even though it is whole. Read with (x as num).toDouble(). |
| 12345678901234567890 | double | The Dart VM decodes an integer outside the 64-bit range as a double. |
| true, false | bool | |
| null | dynamic, or a nullable type | null in every record gives dynamic. null in some records makes the field nullable, for example String?. |
| { ... } | a class | Nested classes are named after their key. Objects with the same shape and name share one class. |
| { } | Map<String, dynamic> | An empty object has nothing to build a class from. |
| [ ... ] | List<T> | T comes from merging every item. An empty list gives List<dynamic>. Items of different types give List<dynamic>. |
Output styles
Three ways to get the same JSON into Dart.
Pick by how much code you want to write and how much you want generated.
Plain Dart
No packages. You get fromJson and toJson written out, so what you read is what runs. A good fit for small apps, scripts and anyone who would rather not run a code generator.
Nothing to install.
json_serializable
Annotated classes; build_runner writes fromJson and toJson for you. Less code to keep in step by hand, at the cost of a generation step after every model change. The tool adds explicitToJson when a class holds other classes.
dart pub add json_annotationdart pub add --dev build_runner json_serializabledart run build_runner build
Freezed
Immutable data classes with value equality and copyWith, built on json_serializable. More generated code and one more dependency, in return for the least boilerplate to write.
dart pub add freezed_annotation json_annotationdart pub add --dev build_runner freezed json_serializabledart run build_runner build
Using the result
Two lines to read and write it.
import 'dart:convert';
// `body` is the JSON string you got from your API.
final user = User.fromJson(jsonDecode(body) as Map<String, dynamic>);
final again = jsonEncode(user.toJson());For json_serializable and Freezed, run the build_runner command from the comment at the top of the generated file first; it writes the parts the class refers to.
Limits
What it does not do.
Read the generated code before you ship it. These are the places where a model built from one sample can mislead.
- It learns from the sample you paste. If the real API sends a field your sample lacks, or leaves out one your sample has, the model is wrong for that field. Paste several records, or turn on "Make every field nullable".
- An object used as a dictionary (keys are IDs or names) becomes a class with one field per key. Write Map<String, T> by hand instead.
- A field that holds two different types has no single Dart type, so it becomes dynamic. There are no union types.
- String fields that are really enums stay String. It cannot know the allowed values.
- It reads strict JSON. Comments, trailing commas and single-quoted strings are reported as errors.
- The output is not run through dart format, so its line breaks and trailing commas will differ from a formatted file. Run dart format on the result.
- With plain Dart and copyWith, passing null keeps the current value, so a nullable field cannot be reset to null through copyWith.
How it was checked
Compiled, analyzed and round-tripped.
The generator is tested against the real Dart toolchain, not just read by eye. Every example on this page, plus a set of awkward inputs (keys that are reserved words, keys that collide once converted to camelCase, numbers such as 10.0, 1e3 and 263, mixed types, empty lists, a list as the root), is generated in all three styles with different option sets, built with build_runner, checked with dart analyze, and read back through fromJson and toJson to confirm the data survives. The last run, on 26 September 2026 with Dart 3.13, Freezed 4 and json_serializable 6.14, covered 144 combinations and found no analyzer issues and no failed round trips.
FAQ
Questions people ask first.
- Is my JSON uploaded anywhere?
- No. The conversion runs in your browser with JavaScript that is already on the page. Nothing you paste is sent to a server or saved, and there is no account. The site counts page views; it does not see what you type.
- How does it handle null safety?
- All output is null-safe Dart. A field is nullable, for example String?, only when the sample has a null for it or leaves the key out of at least one object. Every other field is non-nullable and required. If your sample cannot show every variation the API sends, use "Make every field nullable".
- Why is a number a double when my JSON says 10.0?
- On the Dart VM, which runs Flutter on mobile and desktop, jsonDecode returns an int for a number written without a decimal point and a double for one written with a decimal point or an exponent. JavaScript's own JSON parser cannot tell 10 from 10.0, so this tool has a parser of its own that keeps the difference. The field is typed the way the VM will receive it, and doubles are read with (x as num).toDouble() so a whole number from the API later does not break it. On Flutter web, numbers are JavaScript numbers, and that code works there too.
- Why is a field dynamic?
- When the sample gives nothing to infer a type from: null in every record, an empty list, or values of different types under one key. The "Notes about this conversion" list under the output says which fields and why.
- Should I choose json_serializable or Freezed?
- If you only need to read and write JSON, json_serializable (or plain Dart) is enough. Choose Freezed when you also want immutable models with value equality and copyWith. Both need build_runner; the commands are in the comment at the top of the output.
- Can I convert a JSON array?
- Yes. If the root is a list of objects, the class is built from the merged items, and a comment at the top of the output shows how to decode the whole list.
- Which Dart version do I need?
- We test with Dart 3.13. Plain output uses only null-safety features (Dart 2.12 and later), but we have not tested older SDKs. Current json_serializable generates syntax that needs Dart 3.8 or newer when you skip null fields in toJson.
From the team behind the tool
Building a Flutter app?
Daniotech builds cross-platform mobile apps with Flutter, React Native and Capacitor, and the APIs they talk to. Tell us what you are making and who it is for.