⚙️ Install

Add flutter_data and dependencies to your pubspec.yaml file:

    sdk: flutter
  flutter_data: ^0.3.8
  json_annotation: ^3.0.1  # RECOMMENDED! not required
  provider: 4.1.0-dev  # RECOMMENDED! not required
  path_provider: ^1.6.7  # RECOMMENDED! not required

  build_runner: ^1.8.1  # REQUIRED
  json_serializable: ^3.3.0   # RECOMMENDED! not required

Flutter Data doesn’t require any library besides build_runner for code generation.

However, json_serializable, provider and path_provider are so useful that they are highly recommended!

🔧 Configure

Annotate your models with @DataRepository() (adding any necessary adapters to customize the default repository behavior) and make it extend DataSupport<T>.


import 'package:flutter_data/flutter_data.dart';
import 'package:json_annotation/json_annotation.dart';

part 'todo.g.dart';

class Todo extends DataSupport<Todo> {
  final int id;
  final String title;
  final bool completed;

  Todo({this.id, this.title, this.completed = false});

StandardJSONAdapter is included in Flutter Data and features a serializer/deserializer for the following JSON structure:

  "id": 1,
  "title": "delectus aut autem",
  "completed": false

As you can notice, we used int to represent the actual type of the id identifier field.

You may use int, String or anything else. Keep in mind that Flutter Data will call toString on this id when building URLs.

The fromJson factory constructor and toJson() method are not required (but you can specify them). Flutter Data will automatically use the _$TodoFromJson and _$TodoToJson functions generated by json_serializable.

That’s great, but how do we reach the API?

Let’s make or own mini-adapter to configure the base URL!

mixin JSONPlaceholderAdapter on RemoteAdapter<Todo> {
  String get baseUrl => 'http://jsonplaceholder.typicode.com';

That is a very simple config. Of course this mixin can be made generic and be applied to any model. Adapters can be used to create very powerful customizations.

Okay, so our Todo model will look like this:

@DataRepository([StandardJSONAdapter, JSONPlaceholderAdapter])
class Todo extends DataSupport<Todo> {
  final int id;
  final String title;
  final bool completed;

  Todo({this.id, this.title, this.completed = false});

We can now run a build:

flutter packages pub run build_runner build

Flutter Data auto-generated:

Trouble generating code? See here.

This library exposes the dataProviders method which registered all repositories with Provider:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_data/flutter_data.dart';
import 'package:todo_app/main.data.dart';

void main() {
    providers: [
      ...dataProviders(() => getApplicationDocumentsDirectory(), clear: true),
    child: TodoApp(),

class MyApp extends StatelessWidget {
  Widget build(context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Builder(
            builder: (context) {
              if (context.watch<DataManager>() == null) {
                return const CircularProgressIndicator();
              // Flutter Data providers are ready at this point!
              final repository = context.read<Repository<Todo>>();
              return Text('Hello Flutter Data! $repository');

A few notes:

Initialization is asynchronous and will be ready once DataManager is available.

With Provider, you can check it via context.watch<DataManager>() != null.

Not using Provider? Not using Flutter?

Looking for additional arguments for initialization?

We got you covered! See the Configuration FAQ.

➡ Continue with the tutorial!