flutter-implement-json-serialization
flutter/agent-plugins
Manually create Dart model classes with fromJson/toJson methods for JSON serialization in Flutter.
What is flutter-implement-json-serialization?
This skill teaches how to implement manual JSON serialization in Flutter using `dart:convert`, creating model classes with `fromJson` factory constructors and `toJson` methods. Use it when you need to map JSON keys to class properties for simple data structures, with guidance on handling both small payloads synchronously and large payloads via background isolates.
- Define plain Dart model classes with properties matching JSON structure
- Implement `fromJson` factory constructors with type-safe pattern matching and casting
- Implement `toJson` methods to serialize models back to JSON maps
- Fetch and parse JSON from HTTP responses with proper status code validation
- Offload large JSON parsing to background isolates using `compute()` to prevent UI jank
How to install flutter-implement-json-serialization
npx skills add https://github.com/flutter/agent-plugins --skill flutter-implement-json-serialization- Flutter SDK installed
- Basic knowledge of Dart classes and constructors
- Familiarity with the `http` package for network requests
- Understanding of `dart:convert` library basics
How to use flutter-implement-json-serialization
- 1.Define a plain Dart class with `final` properties matching your JSON structure
- 2.Implement a `factory ClassName.fromJson(Map<String, dynamic> json)` constructor using pattern matching or explicit casting
- 3.Implement a `Map<String, dynamic> toJson()` method that returns a map of your properties
- 4.For small payloads, decode JSON synchronously with `jsonDecode()` and pass to `fromJson()`
- 5.For large payloads, use `compute(parseFunction, responseBody)` to parse in a background isolate
- 6.Write unit tests for both `fromJson` and `toJson` to validate type safety and correctness
Use cases
- Parsing a single user object from a REST API response
- Deserializing a list of thousands of items from a paginated endpoint without blocking the UI
- Converting local JSON configuration files into strongly-typed Dart models
- Building a data layer that maps API responses to domain models with compile-time type safety
- Implementing bidirectional serialization for models that need to be sent back to a server
- Flutter developers building data models for API integration
- Engineers implementing custom JSON serialization without code generation
- Teams preferring explicit control over JSON mapping logic
- Developers working with simple data structures that don't justify code generation overhead
flutter-implement-json-serialization FAQ
Use manual serialization for simple models with few properties or when you need explicit control over the mapping logic. Use code generation (like `json_serializable`) for complex nested structures or large numbers of models to reduce boilerplate.
The `jsonDecode()` function returns `dynamic` type, which loses type information. Casting to `Map<String, dynamic>` or `List<dynamic>` enforces type safety and enables compile-time error checking.
Create separate model classes for nested structures, each with their own `fromJson` and `toJson` methods. In the parent model's `fromJson`, call the nested model's `fromJson` constructor on the nested JSON map.
Synchronous parsing blocks the main thread and is suitable for small payloads (< 16ms). Isolate-based parsing using `compute()` runs on a background thread and prevents UI jank when parsing large JSON documents.
Always throw exceptions on parsing failure. This makes errors explicit and prevents silent failures. Return null only for optional fields within the JSON structure, not for the entire parsing operation.
Full instructions (SKILL.md)
Source of truth, from flutter/agent-plugins.
name: flutter-implement-json-serialization
description: Create model classes with fromJson and toJson methods using dart:convert. Use when manually mapping JSON keys to class properties for simple data structures.
metadata:
model: models/gemini-3.1-pro-preview
last_modified: Tue, 21 Apr 2026 21:44:50 GMT
Serializing JSON Manually in Flutter
Contents
- Core Guidelines
- Workflow: Implementing a Serializable Model
- Workflow: Fetching and Parsing JSON
- Examples
Core Guidelines
- Import
dart:convert: Utilize Flutter's built-indart:convertlibrary for manual JSON encoding (jsonEncode) and decoding (jsonDecode). - Enforce Type Safety: Always cast the
dynamicresult ofjsonDecode()to the expected type, typicallyMap<String, dynamic>for objects orList<dynamic>for arrays. - Encapsulate Serialization Logic: Define plain model classes containing properties corresponding to the JSON structure. Implement a
fromJsonfactory constructor and atoJsonmethod within the model. - Handle Background Parsing: If parsing large JSON documents (execution time > 16ms), offload the parsing logic to a separate isolate using Flutter's
compute()function to prevent UI jank. - Throw Exceptions on Failure: When handling HTTP responses, throw an exception if the status code is not successful (e.g., not 200 OK or 201 Created). Do not return
null.
Workflow: Implementing a Serializable Model
Use this checklist to implement manual JSON serialization for a data model.
Task Progress:
- Define the plain model class with
finalproperties. - Implement the
factory Model.fromJson(Map<String, dynamic> json)constructor. - Implement the
Map<String, dynamic> toJson()method. - Write unit tests for both serialization methods.
- Run validator -> review type mismatch errors -> fix casting logic.
- Define the Model: Create a class with properties matching the JSON keys.
- Implement
fromJson: Extract values from theMapand cast them to the appropriate Dart types. Use pattern matching or explicit casting. - Implement
toJson: Return aMap<String, dynamic>mapping the class properties back to their JSON string keys. - Validate: Execute unit tests to ensure type safety, autocompletion, and compile-time exception handling function correctly.
Workflow: Fetching and Parsing JSON
Use this conditional workflow when retrieving and parsing JSON from a network request.
Task Progress:
- Execute the HTTP request.
- Validate the response status code.
- Determine parsing strategy (Synchronous vs. Isolate).
- Decode and map the JSON to the model.
- Execute Request: Use the
httppackage to perform the network call. - Validate Response:
- If
response.statusCode == 200(or 201 for POST), proceed to parsing. - If the status code indicates failure, throw an
Exception.
- If
- Determine Parsing Strategy:
- If parsing a small payload (e.g., a single object), parse synchronously on the main thread.
- If parsing a large payload (e.g., an array of thousands of objects), use
compute(parseFunction, response.body)to parse in a background isolate.
- Decode and Map: Pass the decoded JSON to your model's
fromJsonconstructor.
Examples
High-Fidelity Model Implementation
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory constructor for deserialization
factory User.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'id': int id,
'name': String name,
'email': String email,
} =>
User(
id: id,
name: name,
email: email,
),
_ => throw const FormatException('Failed to load User.'),
};
}
// Method for serialization
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
Synchronous Parsing (Small Payload)
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<User> fetchUser(http.Client client, int userId) async {
final response = await client.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Decode returns dynamic, cast to Map<String, dynamic>
final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}
Background Parsing (Large Payload)
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(
Uri.parse('https://api.example.com/users'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Offload expensive parsing to a background isolate
return compute(parseUsers, response.body);
} else {
throw Exception('Failed to load users');
}
}
Related skills
More from flutter/agent-plugins and the wider catalog.

flutter-implementing-navigation-and-routing
Agent skill from flutter/agent-plugins.

flutter-improving-accessibility
Agent skill from flutter/agent-plugins.

flutter-interoperating-with-native-apis
Agent skill from flutter/agent-plugins.

flutter-layout
Agent skill from flutter/agent-plugins.

flutter-localizing-apps
Agent skill from flutter/agent-plugins.

flutter-managing-state
Agent skill from flutter/agent-plugins.