flutter_cached_network_image: the two hundred kilobyte dependency that decides whether your list scrolls smoothly
Download, cache and show images in a flutter app
At a glance
- What is it?
- A Flutter library from Baseflow that fetches images over HTTP and keeps them on the device, with a widget form, an ImageProvider form, and a web implementation that does not cache at all.
- Who is it for?
- flutter_cached_network_image does one narrow job and does it in the shape Flutter developers already expect: a widget with placeholder, progress and error callbacks, an ImageProvider that plugs into any existing image widget, and a cache owned by a separate package you can swap out. The limitation worth knowing before you install it is web, where the library offers minimal support and no caching, so browser targets need a different plan.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 11 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 October 8, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A widget and an ImageProvider for the same job
The package is a Dart library with one purpose, stated plainly at the top of the README: show images from the internet and keep them in the cache directory. What makes it more than a thin Image.network wrapper is that it exposes that job through two doors. You can use the CachedNetworkImage widget directly, or you can wrap CachedNetworkImageProvider and hand it to any widget that accepts an ImageProvider.
Image(image: CachedNetworkImageProvider(url))That second door is the one that matters in real codebases. Once the bytes live behind an ImageProvider, any widget in the framework that already knows how to render an image will reuse the cached copy, which means an existing avatar, hero image or background decoration can be pointed at a remote URL without restructuring the widget around it. The repository tree backs up the idea that this is a properly split package rather than one directory. There is `cached_network_image/` for the main library, `cached_network_image_platform_interface/` for the contract that platform implementations satisfy, and `cached_network_image_web/` as a separate implementation. It is the same federated shape that Flutter's own plugin system uses, and it is the reason the web story is different from the mobile story.
The repository has 2,590 stars, 733 forks and 327 open issues, tagged for caching, flutter, image and imageprovider. It is not archived, and the last push landed on 2026-09-24.
Placeholder, progress and error are three separate callbacks
The widget's constructor is where most of the real decisions live, and the README leads with the minimal form. You supply a URL, and you get a placeholder for the wait, an error widget for the failure, and optionally a progress indicator that reports actual bytes rather than an indeterminate spinner.
CachedNetworkImage(
imageUrl: "https://placehold.co/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),Swap the placeholder for the progress builder and the widget starts reporting download progress, which is the difference between a spinner that tells the user nothing and one that tells them a 4 MB image is nearly done. Both callbacks take the same `(context, url)` shape.
CachedNetworkImage(
imageUrl: "https://placehold.co/350x150",
progressIndicatorBuilder: (context, url, downloadProgress) =>
CircularProgressIndicator(value: downloadProgress.progress),
errorWidget: (context, url, error) => Icon(Icons.error),
),There is a fourth builder for a different problem. If you want the placeholder behaviour but also want to hand the resolved provider to another widget, `imageBuilder` gives you the provider and lets you compose it yourself, which is how you get a fitted, colour-filtered image inside a container decoration while still keeping the loading and error handling above it.
Storage belongs to flutter_cache_manager, not to this package
The How it works section of the README is two sentences long and they matter: the cached network image stores and retrieves files using the flutter_cache_manager package. That is the whole architecture. Nothing in this repository decides where a file goes on disk, how long it survives, or how many images a user can accumulate before something has to give.
This has a practical consequence worth sitting with. If your app needs a different eviction policy, a different cache key strategy, or a bound on total cache size, you are changing a dependency rather than configuring a widget. The release history shows the seam: v3.4.0, published 2024-08-01, added a static `defaultCacheManager` field on CachedNetworkImageProvider, which is exactly the kind of change you need when you want to point the provider at your own configured cache manager rather than the shared default.
The same release is worth reading as a maintenance record. It fixed deprecated API usage, exposed the provider's `scale` on the widget, improved debug console messages, and changed how the ImageLoader reports errors so they are emitted on a stream instead of being re-thrown. That last change is the one that connects directly to the most asked question in the README's own FAQ.
Reading a failed image load without assuming the app died
The README carries an FAQ entry that is technically a bug report wearing a question mark, and it is more useful than most feature documentation. Someone sees their app appear to crash when an image fails to load, so they wrote: my app crashes when the image loading failed, I know this is not really a question.
The answer is the part to remember. The Dart VM debugger may pause on the error because it does not recognise the exception as caught, the console will print it, and a crash reporting tool may forward it to your dashboard. None of that means the process died. The maintainers suggest that everything is usually still running fine, and that if a real crash does occur you should open an issue with a small reproducible example, linking two earlier threads where the same report was resolved.
That is an unusually honest troubleshooting note, and it changes how you should instrument a release build. If your error reporting tool is set to capture framework errors, a pile of failed image URLs can drown out the crashes you actually care about. Filtering on your own error keys, rather than treating every framework-reported error as a termination event, is the practical advice hiding in that paragraph.
Web support exists, and it does not cache
The README is direct about the limit: both the CachedNetworkImage widget and the CachedNetworkImageProvider have minimal support for web, and caching is not currently included. That is a real constraint for anyone shipping a Flutter app to browsers, and it is the kind of thing better to learn from the README than from a build failure.
The repository tree explains the shape of the compromise. `cached_network_image_web/` is a separate package that implements the platform interface for browser targets, so the widget tree compiles and renders on the web rather than failing outright. What it does not do is provide the on-device cache that makes the package worth using on mobile. A Flutter web build gets working image loading without the second visit being fast, which is roughly half of the value proposition gone.
The rest of the repository is small and unremarkable in a good way: `.github/`, `.gitignore`, `README.md`, `icon.png`, and two files named AGENTS.md and CLAUDE.md, which read like guidance committed for coding agents rather than anything a Flutter developer needs to read. There are no bundled example apps in the tree to study, which means the README's four snippets are the entire set of worked examples the project offers.
Judging it against the alternatives
The honest comparison is against three things: Flutter's built-in Image.network, other caching wrappers, and writing your own ImageProvider. Against the built-in widget, this package wins on repeat visits and loses on nothing but a dependency, because a bare Image.network refetches every time it rebuilds without a cache. Against other third-party wrappers, the differentiator is that the cache is delegated rather than reimplemented, which means the eviction and disk logic lives in flutter_cache_manager where it can be maintained and tested on its own.
That delegation cuts both ways, though, and this is where the README runs out. It does not tell you what the default cache manager does about maximum file counts, maximum disk usage, or how a cached entry is invalidated when the server-side image changes at the same URL. It points at flutter_cache_manager as the place to look, and that is the honest answer: those are cache policy questions and they belong to the cache package.
The signals around the project are calm rather than exciting. The last push was 2026-09-24 and the release list shows v3.4.0 from 2024-08-01, so this is a package in maintenance with a settled API. The topic tags still point at flutter, caching, image and imageprovider, and 327 open issues suggest an active queue of user reports. For a dependency this small and this widely used, that is a normal amount of noise.
Editorial conclusion
flutter_cached_network_image does one narrow job and does it in the shape Flutter developers already expect: a widget with placeholder, progress and error callbacks, an ImageProvider that plugs into any existing image widget, and a cache owned by a separate package you can swap out. The limitation worth knowing before you install it is web, where the library offers minimal support and no caching, so browser targets need a different plan. The last push on the repository was 2026-09-24 and the most recent release listed is v3.4.0 from 2024-08-01, which means the API surface has been quiet for a while and the interesting changes have been maintenance ones rather than new features. Start by dropping the widget into a list with a real progress indicator, then read the flutter_cache_manager package before you assume anything about eviction, disk limits or how many files a user can end up holding.
Frequently asked questions
Does cached_network_image cache images on Flutter web?
Not currently. The README states that both the CachedNetworkImage widget and CachedNetworkImageProvider have minimal support for web and that caching is not included there. Web targets render images through the separate cached_network_image_web package without the on-device cache.
Why does my app look like it crashed when an image failed to load?
It usually did not crash. The Dart VM debugger can pause on an error it does not recognise as caught, the console prints it, and crash reporting tools may forward it, while the app keeps running. The maintainers ask for a small reproducible example if you do see a genuine crash.
How do I show download progress instead of a spinner?
Use the progressIndicatorBuilder callback, which receives a downloadProgress object whose progress value you can pass to CircularProgressIndicator. The placeholder callback is the right choice when you only need an indeterminate indicator.
Can I use the cached image through any widget, not just CachedNetworkImage?
Yes. Wrap the URL in CachedNetworkImageProvider and pass it to any widget that accepts an ImageProvider, which is how you reuse cached bytes in existing avatar, background or decoration code.
Who decides where the cached files are stored and when they are removed?
The flutter_cache_manager package, not this one. The README says the cached network image stores and retrieves files using flutter_cache_manager, so eviction and disk policy questions belong to that package. Release v3.4.0 added a static defaultCacheManager field for pointing the provider at your own cache manager.
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/baseflow-flutter-cached-network-image)