flutter
/

Dart JSON – Parsing and Serialization

Last Sync: Today

On this page

8
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Dart JSON – Parsing and Serialization

What is JSON?

JSON (JavaScript Object Notation) is a lightweight data interchange format. It's easy for humans to read and write, and easy for machines to parse and generate. In Dart, JSON is commonly used for API communication, configuration files, and data storage. The dart:convert library provides built‑in support for JSON encoding and decoding.

Basic JSON Operations

Dart's dart:convert library provides two core functions: jsonDecode to parse a JSON string into a Dart object, and jsonEncode to convert a Dart object back to a JSON string.

DARTRead-only
1
import 'dart:convert';

void main() {
  // JSON string
  String jsonString = '{"name":"Alice","age":30}';

  // Parse JSON -> Dart Map
  Map<String, dynamic> user = jsonDecode(jsonString);
  print(user['name']); // Alice
  print(user['age']);  // 30

  // Encode Dart object -> JSON string
  Map<String, dynamic> data = {'product': 'Laptop', 'price': 999.99};
  String encoded = jsonEncode(data);
  print(encoded); // {"product":"Laptop","price":999.99}
}

Parsing JSON to Dart Objects

While working with raw maps is fine for simple cases, for larger applications you'll want to convert JSON into typed Dart objects (classes). This gives you type safety and better code organization.

DARTRead-only
1
class User {
  final String name;
  final int age;

  User(this.name, this.age);

  // Factory constructor to create a User from JSON
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      json['name'] as String,
      json['age'] as int,
    );
  }

  // Method to convert User to JSON
  Map<String, dynamic> toJson() => {
        'name': name,
        'age': age,
      };
}

void main() {
  String jsonString = '{"name":"Bob","age":25}';
  Map<String, dynamic> jsonMap = jsonDecode(jsonString);
  User user = User.fromJson(jsonMap);
  print(user.name); // Bob
  print(user.age);  // 25

  // Serialize back to JSON
  print(jsonEncode(user.toJson())); // {"name":"Bob","age":25}
}

Handling Nested JSON

Real‑world JSON often contains nested objects and arrays. You can handle these by creating corresponding classes and using them inside the fromJson and toJson methods.

DARTRead-only
1
class Address {
  final String street;
  final String city;

  Address(this.street, this.city);

  factory Address.fromJson(Map<String, dynamic> json) => Address(
        json['street'] as String,
        json['city'] as String,
      );

  Map<String, dynamic> toJson() => {'street': street, 'city': city};
}

class Person {
  final String name;
  final Address address;

  Person(this.name, this.address);

  factory Person.fromJson(Map<String, dynamic> json) => Person(
        json['name'] as String,
        Address.fromJson(json['address']),
      );

  Map<String, dynamic> toJson() => {
        'name': name,
        'address': address.toJson(),
      };
}

Working with Lists of Objects

When the JSON contains an array of objects, you can map each element to your Dart class.

DARTRead-only
1
void main() {
  String jsonString = '[{"name":"Alice","age":30},{"name":"Bob","age":25}]';
  List<dynamic> jsonList = jsonDecode(jsonString);
  List<User> users = jsonList.map((item) => User.fromJson(item)).toList();
  print(users.length); // 2
  print(users[0].name); // Alice
}

Error Handling

JSON parsing can fail if the data is malformed or if the structure doesn't match expectations. Always handle exceptions.

DARTRead-only
1
void parseUser(String jsonString) {
  try {
    Map<String, dynamic> jsonMap = jsonDecode(jsonString);
    User user = User.fromJson(jsonMap);
    print('User: ${user.name}');
  } on FormatException catch (e) {
    print('Invalid JSON: $e');
  } catch (e) {
    print('Unexpected error: $e');
  }
}

void main() {
  parseUser('{"name":"Alice","age":30}'); // OK
  parseUser('{"name":"Bob"}'); // Missing age – will throw a type error
}

Using json_serializable (Code Generation)

Manually writing fromJson and toJson methods can become tedious, especially for large classes. The json_serializable package generates these methods for you. Add the following dependencies to your pubspec.yaml:

YAMLRead-only
1
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  build_runner: ^2.4.0
  json_serializable: ^6.7.0

Then annotate your class with @JsonSerializable() and use the generated part file.

DARTRead-only
1
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final String name;
  final int age;

  User(this.name, this.age);

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

Run dart run build_runner build to generate the user.g.dart file containing the serialization logic.

Key Takeaways

    • Use jsonDecode to parse JSON strings and jsonEncode to convert objects to JSON.
    • Create factory constructors (fromJson) and toJson methods to convert between JSON and Dart objects.
    • Handle nested JSON by creating corresponding nested classes.
    • Always catch FormatException when parsing JSON from external sources.
    • For larger projects, use json_serializable to automate boilerplate serialization code.

Try it yourself

import 'dart:convert';

void main() {
  String jsonString = '{"name":"Flutter","year":2024}';
  Map<String, dynamic> data = jsonDecode(jsonString);
  print('Name: ${data['name']}');
  print('Year: ${data['year']}');

  Map<String, dynamic> response = {'status': 'success', 'data': data};
  String encoded = jsonEncode(response);
  print('Encoded: $encoded');
}

Test Your Knowledge

Q1
of 4

Which function is used to parse a JSON string into a Dart object?

A
jsonParse()
B
jsonDecode()
C
jsonEncode()
D
jsonStringify()
Q2
of 4

What does `jsonEncode` return?

A
A Map
B
A List
C
A String
D
A dynamic object
Q3
of 4

When using `json_serializable`, which annotation is required on the class?

A
@JsonSerializable
B
@JsonCodec
C
@Serializable
D
@Json
Q4
of 4

How do you handle a missing key in JSON to avoid runtime errors?

A
Use try-catch
B
Check `json.containsKey(key)` or provide a default value
C
Use a `null` check
D
It's not possible

Frequently Asked Questions

What is the difference between `jsonDecode` and `jsonDecode`? (typo fix) Actually the correct is `jsonDecode` vs `jsonEncode`. `jsonDecode` parses JSON to Dart objects; `jsonEncode` converts Dart objects to JSON strings.

jsonDecode takes a JSON string and returns a Dart object (usually Map<String, dynamic> or List<dynamic>). jsonEncode takes a Dart object (like a map, list, or custom object with toJson) and returns a JSON string.

Why do I get a `_InternalLinkedHashMap` instead of a custom class?

jsonDecode returns plain maps and lists. You need to manually map these to your custom classes using fromJson constructors or use a package like json_serializable.

How do I handle optional fields in JSON?

You can use nullable types and null‑aware operators. For example, int? age and in fromJson, do age: json['age'] as int?. For default values, you can provide a fallback: json['age'] ?? 0.

What is the purpose of the `@JsonKey` annotation?

It allows you to customize the serialization of a field, for example if the JSON key name is different from the field name (@JsonKey(name: 'user_name')), to ignore a field, or to provide a default value.

Can I parse JSON to a typed list directly?

jsonDecode returns List<dynamic>. You can map it to a typed list with .map((item) => MyClass.fromJson(item)).toList().

Is `json_serializable` only for Flutter?

No, it works for any Dart project (including console, server, and Flutter). It uses Dart's build system to generate code at compile time.

Previous

dart enums

Next

dart file handling

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.