Reader Stacks

Displaying Local and Remote Images in Flutter

AssetImage for bundled files, NetworkImage for remote URLs — the same Image widget, with a loading and error state that only the network version actually needs to handle.

Displaying Local and Remote Images in Flutter

Displaying a bundled local image versus one loaded from a remote URL uses the same Image widget in Flutter, but with different constructors — and the remote version needs to account for loading and error states that a local asset never has to worry about.

Registering assets in pubspec.yaml

flutter:
    assets:
        - assets/images/logo.png
        - assets/images/

An image needs to be listed (or its containing folder listed) in pubspec.yaml before Flutter will bundle it into the app — a common early mistake is adding the file to the project folder but forgetting this registration step, resulting in the image simply failing to load with no obvious reason why.

Displaying a local (bundled) image

Image.asset('assets/images/logo.png')
// or, more explicitly
Image(image: AssetImage('assets/images/logo.png'))

Displaying a remote image

Image.network('https://example.com/photo.jpg')

Handling loading and error states for a remote image

Image.network(
    'https://example.com/photo.jpg',
    loadingBuilder: (context, child, loadingProgress) {
        if (loadingProgress == null) return child;
        return CircularProgressIndicator(
            value: loadingProgress.expectedTotalBytes != null
                ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
                : null,
        );
    },
    errorBuilder: (context, error, stackTrace) {
        return Icon(Icons.broken_image);
    },
)

A local asset image is bundled into the app itself and essentially can't fail to load (short of a build misconfiguration) — a network image genuinely can fail (no connection, a 404, a slow connection worth showing progress for), which is exactly why only the network version needs these loading and error handling callbacks.

Caching network images across the app

flutter pub add cached_network_image
CachedNetworkImage(
    imageUrl: 'https://example.com/photo.jpg',
    placeholder: (context, url) => CircularProgressIndicator(),
    errorWidget: (context, url, error) => Icon(Icons.broken_image),
)

Flutter's built-in Image.network re-downloads the same image on every rebuild unless the underlying image cache happens to still hold it — the cached_network_image package adds a genuine disk cache, meaningfully reducing repeated network requests for images shown repeatedly (a list of avatars scrolling in and out of view, for instance).

Sizing and fitting an image within its container

Image.network(
    'https://example.com/photo.jpg',
    width: 200,
    height: 200,
    fit: BoxFit.cover,
)

BoxFit.cover scales the image to fill the given dimensions, cropping any overflow — BoxFit.contain instead scales to fit entirely within the dimensions without cropping, potentially leaving empty space — choosing between them depends on whether cropping or empty space is the more acceptable trade-off for a specific layout.