PluginBench
Skill
Review
Audit score 70

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
Prerequisites
  • Flutter SDK installed
  • Basic knowledge of Dart classes and constructors
  • Familiarity with the `http` package for network requests
  • Understanding of `dart:convert` library basics
Claude Code
Cursor
Windsurf
Cline

How to use flutter-implement-json-serialization

  1. 1.Define a plain Dart class with `final` properties matching your JSON structure
  2. 2.Implement a `factory ClassName.fromJson(Map<String, dynamic> json)` constructor using pattern matching or explicit casting
  3. 3.Implement a `Map<String, dynamic> toJson()` method that returns a map of your properties
  4. 4.For small payloads, decode JSON synchronously with `jsonDecode()` and pass to `fromJson()`
  5. 5.For large payloads, use `compute(parseFunction, responseBody)` to parse in a background isolate
  6. 6.Write unit tests for both `fromJson` and `toJson` to validate type safety and correctness

Use cases

Good for
  • 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
Who it's for
  • 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

When should I use manual JSON serialization vs. code generation?

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.

Why do I need to cast the result of jsonDecode()?

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.

How do I handle nested JSON objects?

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.

What's the difference between synchronous and isolate-based parsing?

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.

Should I throw exceptions or return null on JSON parsing failure?

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

  • Import dart:convert: Utilize Flutter's built-in dart:convert library for manual JSON encoding (jsonEncode) and decoding (jsonDecode).
  • Enforce Type Safety: Always cast the dynamic result of jsonDecode() to the expected type, typically Map<String, dynamic> for objects or List<dynamic> for arrays.
  • Encapsulate Serialization Logic: Define plain model classes containing properties corresponding to the JSON structure. Implement a fromJson factory constructor and a toJson method 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 final properties.
  • 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.
  1. Define the Model: Create a class with properties matching the JSON keys.
  2. Implement fromJson: Extract values from the Map and cast them to the appropriate Dart types. Use pattern matching or explicit casting.
  3. Implement toJson: Return a Map<String, dynamic> mapping the class properties back to their JSON string keys.
  4. 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.
  1. Execute Request: Use the http package to perform the network call.
  2. Validate Response:
    • If response.statusCode == 200 (or 201 for POST), proceed to parsing.
    • If the status code indicates failure, throw an Exception.
  3. 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.
  4. Decode and Map: Pass the decoded JSON to your model's fromJson constructor.

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');
  }
}