# ferry: a stream-based, strongly typed GraphQL client for Dart and Flutter

> ferry is a Dart and Flutter GraphQL client built on streams, with generated immutable data classes, a normalised optimistic cache, and a set of packages split so the cache, the store and the Flutter widgets can be adopted separately. The repository is a melos monorepo, and the code generation is the part you have to think about before choosing it.

**gql-dart/ferry** — Stream-based strongly typed GraphQL client for Dart

- Repository: https://github.com/gql-dart/ferry
- Website: https://ferrygraphql.com/
- Stars: 635 · Forks: 136
- Language: Dart
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/gql-dart-ferry

## Streams as the transport, which is the design choice underneath everything

ferry describes itself as a simple, powerful GraphQL client for Flutter and Dart, and the repository description is more specific: a stream-based strongly typed GraphQL client. Streams rather than futures is not a stylistic detail here, because it changes how a query reaches your UI. A future delivers one value and completes. A stream can deliver a value, then another when the cache is updated, then another when a refetch returns. That is what makes the optimistic cache and the live updates expressible without a separate mechanism. The topics list includes rxdart, so the reactive side of the stack is a dependency rather than something hand rolled. The README's feature list also names the last item on the list, running queries in a separate Isolate to free up resources on the UI thread, which is the sort of thing a Dart client needs because the JSON decoding work can be heavy enough to cause dropped frames on a busy screen.

## Code generation is the price of admission

The second feature in the README's list is built-in code generators that automatically produce immutable data classes for all your GraphQL operations and fragments, based on your schema. The first feature is fully typed, with compile time checks and IDE autocomplete, including fully typed cache reads and writes. Those two features are the same feature seen from two sides. The generator is the package ferry_generator, described as a Dart type generator for GraphQL operations, and it is what produces the classes your code refers to. The cost is that the library is not usable without a generation step, which means your build has to run the generator and your schema has to be available to it. The repository is a monorepo for ferry and related packages, managed with melos, and the packages live under a packages directory, so the generator ships from the same source tree as the client it feeds.

## A normalised cache with optimistic updates

The fourth feature is a normalized optimistic cache, which keeps data in sync through cache normalization and updates your UI instantly with optimistic data. The separate package ferry_cache holds a normalized, strongly typed, optimistic cache, and there is a companion package called normalize whose description is normalization and denormalization of GraphQL data. The split is worth noting because normalization is a well known source of subtlety. The cache stores entities by identifier and holds references to them, so a single update to a user record is visible everywhere that record appears, rather than requiring a refetch of every query that mentioned it. The optimistic part means the cache applies the change you believe is coming before the server confirms it, and then reconciles. The README describes the cache reads and writes as fully typed, so a cache miss or a wrong key is a compile error rather than a null at runtime.

## Eight packages, so you can take the parts you need

The monorepo publishes eight packages on pub, and the README's table is the clearest guide to which is which. package:ferry is the stream-based GraphQL client. package:ferry_cache is the normalized, strongly typed, optimistic cache. package:ferry_exec is a strongly typed GraphQL execution interface, which is the layer that actually runs an operation. package:ferry_flutter holds the Flutter widgets for GraphQL operations. package:ferry_generator is the Dart type generator. package:ferry_store is data persistence for the cache, built as an extensible Store interface with a built-in MemoryStore and a HiveStore that uses hive for offline persistence. package:ferry_hive_store is the hive implementation of ferry_store. And package:normalize handles normalization and denormalization of GraphQL data. That last group is the one to look at if you only want the data layer, because the store and the normalize packages do not drag in Flutter.

## Flutter widgets for queries, mutations and subscriptions

The seventh feature is Flutter widgets for queries, mutations and subscriptions, available out of the box, which is what separates ferry from a pure Dart client. A subscription being available as a widget is a notable inclusion, since subscriptions are the part of GraphQL most clients handle awkwardly. The remaining features cover the network and the data lifecycle. The network interface is customizable using gql_link, allowing you to compose and extend Links, which means you can build on existing links instead of writing the transport layer yourself. Refetch and pagination are also supported, letting you update responses with new data or combine multiple responses into one paged result. The Store interface is extensible, with the MemoryStore as the in-memory default and the HiveStore as the option that persists to disk for offline use.

## The repository is a melos monorepo with a website and examples

The project structure tells you how the pieces fit. There is a melos.yaml at the root, which is the Dart monorepo tool, alongside a pubspec.yaml and a pubspec.lock, a packages directory holding the eight published packages, a website directory for the documentation site, a docs directory, an examples directory and a CHANGELOG.md. The examples are three, and their names are informative. There is auth_token_with_isolate, which is the one that pairs the authentication pattern with the separate isolate option, and there are two pokemon_explorer examples, which suggests a tutorial built in two parts against a public GraphQL API. The CHANGELOG.md at the root means the release notes for the packages are collected in one place. The project is MIT licensed, the repository is not archived, and the last push was on 2026-07-05, with the documentation hosted at ferrygraphql.com and a Discord server linked from the README badges. There are no GitHub releases, so the pub.dev versions and the changelog are the version history to rely on.

## Conclusion

ferry fits a Dart or Flutter team that wants GraphQL with compile time checked responses and a cache that does not require hand-written state handling, and that is comfortable running a code generator against its schema. It does not fit a team that wants a client with no build step, because the generated classes are the point of the library. Verify first that your schema and operations can be processed by the generator, decide early whether you want the Hive store for offline persistence, and read how the isolate option affects how you pass data into queries before you design around it.

## FAQ

### What is ferry and what makes it different from a normal GraphQL client?

ferry is a stream-based strongly typed GraphQL client for Dart and Flutter. Its features include fully typed responses and cache reads and writes, built-in code generators that produce immutable data classes for operations and fragments, a normalized optimistic cache, a customizable network interface using gql_link, and Flutter widgets for queries, mutations and subscriptions.

### Which packages does the ferry monorepo publish?

Eight, on pub. They are ferry, the stream-based client, ferry_cache for the normalized optimistic cache, ferry_exec for the strongly typed execution interface, ferry_flutter for the widgets, ferry_generator for the Dart type generator, ferry_store for cache persistence with an extensible Store interface, ferry_hive_store as the hive implementation, and normalize for normalization and denormalization of GraphQL data.

### How does ferry handle offline persistence?

The ferry_store package provides an extensible Store interface with a built-in MemoryStore and a HiveStore, which uses hive for offline persistence, and there is a separate ferry_hive_store package for that hive implementation.

### Does ferry run queries off the UI thread?

Yes. One of the listed features is running queries in a separate Isolate to free up resources on the UI thread, and the repository includes an example named auth_token_with_isolate showing that pattern with authentication.

## Sources

- [gql-dart/ferry on GitHub](https://github.com/gql-dart/ferry)
- [Issues](https://github.com/gql-dart/ferry/issues)
- [License: MIT](https://github.com/gql-dart/ferry/blob/master/LICENSE)
- [Project website](https://ferrygraphql.com/)
- [README](https://github.com/gql-dart/ferry/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/gql-dart-ferry
