cfug/dio: A Dart and Flutter HTTP Client With Interceptors and Adapters
A powerful HTTP client for Dart and Flutter, which supports global settings, Interceptors, FormData, aborting and canceling a request, files uploading and downloading, requests timeout, custom adapters, etc.
At a glance
- What is it?
- dio is a Dart HTTP client for Flutter and server-side Dart, maintained by the Chinese Flutter User Group since 2023. Its interceptor chain, adapter plugins and timeout options are the parts worth understanding before you adopt it.
- Who is it for?
- Adopt dio when you need request cancellation, an interceptor chain, or a swappable adapter for HTTP/2 or web, and you accept the migration guide as part of your upgrade routine. Stay with dart:io HttpClient or package:http when your calls are a handful of simple GETs and you do not want a dependency with breaking changes across major and minor versions.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 23 days ago.
- What is it written in?
- Mainly Dart, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What dio solves for Dart and Flutter apps
The Dart standard library gives you HttpClient in dart:io, and package:http wraps it in a smaller API. Neither ships a request pipeline you can insert into. dio's README describes the package as a powerful HTTP client for Dart and Flutter that supports global settings, Interceptors, FormData, aborting and canceling a request, file uploading and downloading, requests timeout and custom adapters. The word doing the work there is Interceptors. A Flutter app that needs to attach a token to every request, retry on 401, and log the result without touching each call site is the case dio was built for. The second case is cancellation: a screen that closes while its request is in flight, where a naive client either leaks the response or fires setState on a dead widget. The repository is a monorepo, not a single package. The root README states it is the base repo of the dio project and that readers should move to specific paths for project instructions. The packages live under dio/ and plugins/, with example_dart/ and example_flutter_app/ alongside them.
The interceptor chain and the adapter seam
dio splits a request into two replaceable layers. Interceptors sit around the whole lifecycle: they see a request before it goes out, a response on the way back, and an error when one occurs, and they can modify, short-circuit or rethrow. That is the mechanism behind a logging interceptor, an auth-refresh interceptor, or a retry policy, and it is why the package's topic list includes middleware. Adapters sit underneath and do the actual transport. The default adapter uses dart:io on native platforms; the plugins/ directory ships alternatives. plugins/http2_adapter adds HTTP/2, plugins/web_adapter covers the browser, and plugins/native_dio_adapter routes through the platform's own networking stack. Swapping the adapter changes how bytes move without changing the call sites or the interceptor stack. Two more plugins round out the set: plugins/cookie_manager for cookie persistence and plugins/compatibility_layer, which the README lists without describing its behaviour. FormData and file transfer are part of the core package rather than a plugin, which matters because multipart upload is where hand-rolled clients usually break first. The layering is the design decision to evaluate. If you only need a GET and a POST, you are paying for an abstraction you will not use.
Installing dio and making a first request
dio publishes to pub.dev, and the repository README links each package to its pub.dev page rather than reproducing install steps at the root. The README gives the dio package its own path in the repository, dio/, and its own pub.dev page. The most recent release listed in the repository is dio 5.11.1. The README does not print a pubspec snippet or an install command, so the place to get the package and its version constraint is the pub.dev page linked from the README, or the pubspec.yaml inside the dio/ directory. The same applies to the plugins: each one is linked to its own pub.dev page from the plugin entry in the README. For a working first call, the repository keeps runnable code in example_dart/ and example_flutter_app/. Those directories are the reference for how a Dio instance is constructed, how global settings are passed, and how an interceptor is registered; the root README does not inline any of it. Read the example before you write your own client, because the interceptor registration order is the part that is easiest to get wrong and the examples are where the project shows the intended shape.
Breaking changes are documented, and you will meet them
The root README opens with a warning: before you upgrade, breaking changes might happen in major and minor versions of packages, and it points to a Migration Guide and a COMPATIBILITY_POLICY.md at the repository root. That is an unusual stance. Most Dart packages treat minor versions as safe. dio does not promise that, and the warning is the first thing in the README for a reason. If you pin dio in a large Flutter codebase, budget for reading the migration guide on upgrade rather than assuming pub will resolve you into a compatible set. A second limitation is scope. dio is an HTTP client, not a networking framework: it does not manage caching, offline queues or connection pooling policy for you, and the plugins directory shows that anything beyond the core transport is a separate package with its own version and its own release cadence. The releases listed in the repository show this clearly, with dio, http2_adapter and web_adapter all versioned independently. If your project cannot take a dependency that may require code changes on a minor bump, dio is the wrong tool regardless of how good the interceptor design is.
dio versus package:http and dart:io HttpClient
The comparison people search for is dio against http. package:http is the Dart team's client. It has a small surface, a stable API and no interceptor concept: to add a header to every call you wrap the client yourself or write a subclass of BaseClient. dio's interceptors are that wrapper, built in and ordered, with separate hooks for request, response and error. The difference shows up in two places. First, cancellation: dio exposes aborting and canceling a request, while package:http's request objects do not give you the same first-class cancel path. Second, transport swapping: dio's adapter layer lets you move a Flutter app from dart:io to a browser adapter or an HTTP/2 adapter without rewriting call sites, which package:http handles differently through its own platform-specific implementations. dart:io's HttpClient is lower level still, with no interceptor or FormData convenience. None of this makes package:http a worse choice for a script that fetches a JSON file. It is a worse fit when the same client has to serve twenty screens with shared auth, logging and retry behaviour.
Maintenance, licence and what an upgrade costs
The repository is not archived, and the last push was on 2026-09-06, which is recent. The README states the project was originally authored by @wendux under the flutterchina organization and has been maintained by the Chinese Flutter User Group (cfug) since 2023. The licence is MIT, stated in the README and present as a LICENSE file at the repository root, so you can use dio in closed-source applications; that is a summary of the licence identifier, not legal advice, and your own counsel should confirm anything you depend on commercially. The upgrade cost is the part to weigh. Three packages released on 2026-09-04 according to the repository: dio 5.11.1, http2_adapter 2.9.0 and web_adapter 2.2.2. Each carries its own version, so a Flutter app using dio plus an adapter tracks two upgrade paths. The repository is organised as a melos workspace, visible from melos.yaml and pubspec.yaml at the root, with dio_test/ holding the test package. That layout tells you contributions and releases are coordinated across packages, but it does not tell you the release cadence will match your own.
Editorial conclusion
Adopt dio when you need request cancellation, an interceptor chain, or a swappable adapter for HTTP/2 or web, and you accept the migration guide as part of your upgrade routine. Stay with dart:io HttpClient or package:http when your calls are a handful of simple GETs and you do not want a dependency with breaking changes across major and minor versions. Before writing code, read COMPATIBILITY_POLICY.md, then open the dio/ directory README rather than the repository root README, which only points at the package paths.
Frequently asked questions
Why do we use dio in Flutter?
Because it provides a request pipeline that the Dart standard library does not: interceptors for shared auth, logging and retry behaviour, plus aborting and canceling a request, FormData for uploads, request timeouts and custom adapters. The repository README lists exactly these as the package's supported features.
What are dio interceptors in Flutter and how do they work?
Interceptors sit in the request pipeline and can act on a request before it is sent, on the response coming back, and on errors. That is the layer the README refers to when it lists Interceptors among dio's features, and it is what lets you attach a token or log traffic without editing each call site.
How to call an API in Flutter using dio?
The README points to the dio package path and its pub.dev page rather than printing a snippet, and the repository keeps runnable code in example_dart/ and example_flutter_app/. Those examples show how a Dio instance is created and how a request is issued.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cfug-dio)