Dart JSON
last modified October 18, 2026
In this article we show how to work with JSON in Dart language. We use
the dart:convert library.
JSON
JSON (JavaScript Object Notation) is a lightweight data-interchange
format. It is easily read and written by humans and parsed and generated by
machines. The application/json is the official Internet media type
for JSON. The JSON filename extension is .json.
Dart also has JSON code generation packages such as
json_serializable and built_value.
In this article we focus on the built-in dart:convert library.
For each class that is going to be converted to/from JSON, we define two
members: a fromJson constructor and a toJson method.
The fromJson is used for constructing a new object instance from a
map structure. The toJson method converts a class instance into a
map. These are used in conjunction with the dart:convert
functions jsonDecode and jsonEncode.
The jsonDecode function parses a JSON string and returns the
resulting Dart object: a Map<String, dynamic>, a
List<dynamic>, a String, a number, a
bool, or null. The jsonEncode function
converts an object to a JSON string. If the object is not one of the built-in
types, jsonEncode calls its toJson method.
The json constant is a JsonCodec instance;
json.decode and json.encode do the same as the
shorthand functions.
Dart JSON simple example
The following is a simple Dart example that works with JSON data.
import 'dart:convert';
class User {
final String name;
final String occupation;
User(this.name, this.occupation);
User.fromJson(Map<String, dynamic> m)
: name = m['name'] as String,
occupation = m['occupation'] as String;
Map<String, dynamic> toJson() => {
'name': name,
'occupation': occupation,
};
@override
String toString() => '$name|$occupation';
}
void main() {
const u1Json = '{"name": "John Doe", "occupation": "gardener"}';
final u1 = User.fromJson(jsonDecode(u1Json));
print(u1);
final u2 = User('Roger Roe', 'gardener');
final u2Json = jsonEncode(u2);
print(u2Json);
}
In the program, we convert a JSON string to a Dart object and vice versa.
import 'dart:convert';
We import the dart:convert library.
User.fromJson(Map<String, dynamic> m)
: name = m['name'] as String,
occupation = m['occupation'] as String;
This creates a new User instance from the map structure. The
values in the map are dynamic, so we cast them to the expected
type.
Map<String, dynamic> toJson() => {
'name': name,
'occupation': occupation,
};
The toJson method creates a map structure from an object instance.
const u1Json = '{"name": "John Doe", "occupation": "gardener"}';
We define a JSON string.
final u1 = User.fromJson(jsonDecode(u1Json));
We use jsonDecode to convert the string to a map and pass it to
the User.fromJson constructor to create a User
object.
final u2 = User('Roger Roe', 'gardener');
final u2Json = jsonEncode(u2);
Now we have the reverse operation. We define a User object and
transform it into a JSON string using jsonEncode. The function
finds the toJson method of the class.
$ dart main.dart
John Doe|gardener
{"name":"Roger Roe","occupation":"gardener"}
Dart list of JSON objects
In the next example, we convert a list of maps into a JSON string.
import 'dart:convert';
void main() {
final users = [
{'name': 'John Doe', 'occupation': 'gardener'},
{'name': 'Roger Roe', 'occupation': 'driver'},
{'name': 'Thomas Brown', 'occupation': 'teacher'}
];
final res = jsonEncode(users);
print(res);
}
We have a list of users. Each user is defined by a
Map<String, String>. We convert the list into a JSON string
with jsonEncode.
$ dart main.dart
[{"name":"John Doe","occupation":"gardener"},{"name":"Roger Roe","occupation":"driver"},{"name":"Thomas Brown","occupation":"teacher"}]
Dart pretty-printed JSON
The jsonEncode function produces a compact string. For
human-readable output, we create a JsonEncoder.withIndent.
import 'dart:convert';
void main() {
final data = {
'name': 'John Doe',
'languages': ['Dart', 'Go'],
'address': {'city': 'Bratislava', 'country': 'Slovakia'},
};
const encoder = JsonEncoder.withIndent(' ');
print(encoder.convert(data));
}
The argument of withIndent is the string used for one level of
indentation.
$ dart main.dart
{
"name": "John Doe",
"languages": [
"Dart",
"Go"
],
"address": {
"city": "Bratislava",
"country": "Slovakia"
}
}
Dart list of objects
In the next example, we work with a list of User objects.
import 'dart:convert';
class User {
final String name;
final String occupation;
User(this.name, this.occupation);
User.fromJson(Map<String, dynamic> m)
: name = m['name'] as String,
occupation = m['occupation'] as String;
Map<String, dynamic> toJson() => {
'name': name,
'occupation': occupation,
};
@override
String toString() => '$name|$occupation';
}
void main() {
final users = <User>[
User('John Doe', 'gardener'),
User('Roger Roe', 'driver'),
User('Finn Bradley', 'teacher')
];
final res = jsonEncode(users);
print(res);
print('-' * 34);
final data = jsonDecode(res) as List<dynamic>;
final users2 = [
for (final e in data) User.fromJson(e as Map<String, dynamic>)
];
print(users2);
}
We convert a list of users into a JSON string and vice versa.
final users = <User>[
User('John Doe', 'gardener'),
User('Roger Roe', 'driver'),
User('Finn Bradley', 'teacher')
];
We define a list of user objects.
final res = jsonEncode(users);
The list is encoded into a JSON string with jsonEncode. For each
element, toJson is called.
final data = jsonDecode(res) as List<dynamic>;
We decode the JSON string into a list.
final users2 = [ for (final e in data) User.fromJson(e as Map<String, dynamic>) ];
The list is transformed into a list of User instances with a
collection for.
$ dart main.dart
[{"name":"John Doe","occupation":"gardener"},{"name":"Roger Roe","occupation":"driver"},{"name":"Finn Bradley","occupation":"teacher"}]
----------------------------------
[John Doe|gardener, Roger Roe|driver, Finn Bradley|teacher]
Dart nested JSON
JSON documents often contain nested objects and arrays. The
fromJson constructor of the outer class delegates to the
constructors of the inner classes.
import 'dart:convert';
class Address {
final String city;
final String country;
Address.fromJson(Map<String, dynamic> m)
: city = m['city'] as String,
country = m['country'] as String;
Map<String, dynamic> toJson() => {'city': city, 'country': country};
}
class Person {
final String name;
final List<String> languages;
final Address address;
Person.fromJson(Map<String, dynamic> m)
: name = m['name'] as String,
languages = List<String>.from(m['languages'] as List),
address = Address.fromJson(m['address'] as Map<String, dynamic>);
Map<String, dynamic> toJson() => {
'name': name,
'languages': languages,
'address': address,
};
}
void main() {
const source = '''
{
"name": "John Doe",
"languages": ["Dart", "Go"],
"address": {"city": "Bratislava", "country": "Slovakia"}
}
''';
final p = Person.fromJson(jsonDecode(source));
print(p.name);
print(p.languages.join(', '));
print(p.address.city);
print(jsonEncode(p));
}
The Person class contains a list of strings and a nested
Address object. In toJson we return the
address object itself; jsonEncode calls its
toJson method.
$ dart main.dart
John Doe
Dart, Go
Bratislava
{"name":"John Doe","languages":["Dart","Go"],"address":{"city":"Bratislava","country":"Slovakia"}}
Dart invalid JSON
The jsonDecode function throws a FormatException when
the input is not valid JSON.
import 'dart:convert';
void main() {
const bad = '{"name": "John Doe", "age": }';
try {
jsonDecode(bad);
} on FormatException catch (e) {
print('Invalid JSON: ${e.message}');
}
}
We catch the exception and print its message.
$ dart main.dart Invalid JSON: Unexpected character
Dart JSON file
We can read JSON from a file and write it back with the dart:io
library.
import 'dart:convert';
import 'dart:io';
void main() async {
final file = File('users.json');
final users = [
{'id': 1, 'name': 'John Doe'},
{'id': 2, 'name': 'Roger Roe'},
];
await file.writeAsString(jsonEncode(users));
final content = await file.readAsString();
final data = jsonDecode(content) as List<dynamic>;
for (final u in data) {
print('${u['id']}: ${u['name']}');
}
}
We write a list of maps to the users.json file, read the file
back, and decode its content.
$ dart main.dart 1: John Doe 2: Roger Roe
Dart fetch JSON data from URL
In the next example, we fetch JSON data from a URL resource with the
http package. We use the free test service
jsonplaceholder.typicode.com.
import 'dart:convert';
import 'package:http/http.dart' as http;
class User {
final int id;
final String name;
final String email;
User(this.id, this.name, this.email);
User.fromJson(Map<String, dynamic> m)
: id = m['id'] as int,
name = m['name'] as String,
email = m['email'] as String;
Map<String, dynamic> toJson() => {'id': id, 'name': name, 'email': email};
@override
String toString() => '$id|$name|$email';
}
void main() async {
final resp =
await http.get(Uri.https('jsonplaceholder.typicode.com', '/users'));
final data = jsonDecode(resp.body) as List<dynamic>;
final users = [
for (final e in data) User.fromJson(e as Map<String, dynamic>)
];
print(users.length);
print(users.first);
print(jsonEncode(users.first));
}
In the example, we generate a GET request to a web resource. The resource is
in JSON format: a list of ten users with many fields. Our User
class picks only three of them; the other fields are ignored.
final data = jsonDecode(resp.body) as List<dynamic>;
We decode the response body into a list. If the resource were a named list,
for instance {"users": [...]}, we would pick the
users field of the decoded map.
$ dart main.dart
10
1|Leanne Graham|Sincere@april.biz
{"id":1,"name":"Leanne Graham","email":"Sincere@april.biz"}
Source
In this article we have worked with JSON data in Dart. We utilized the
dart:convert library.
Author
List all Dart tutorials.