---
title: "Assets in Flutter Apps"
description: "How Flutter bundles images, fonts, JSON and shaders declared in pubspec.yaml, how resolution variants and icon tree shaking work, and what to do when an asset needs to change between store releases"
---

Assets are the files your app ships alongside its code: images, fonts, JSON files, animations, shaders. Flutter packs them into the app when it builds, and your Dart code reads them at runtime. Because they ship inside the app binary, they’re also one of the things a Shorebird patch can’t change, so it pays to know which of your files are assets.

## Declaring and loading assets

Flutter bundles only the files you list under `flutter: assets:` in `pubspec.yaml` ([Adding assets and images](https://docs.flutter.dev/ui/assets/assets-and-images)):

```
flutter:
  assets:
    - assets/logo.png
    - assets/images/
    - assets/config.json
```

A directory entry includes only the files directly inside it, not its subdirectories; add each subdirectory as its own entry. Since Flutter 3.41, an entry can also be limited to some platforms with `path:` and `platforms:`.

Load them by the same path:

```
// An image, in a widget's build method
const Image(image: AssetImage('assets/logo.png'));

// Text, outside a widget
final json = await rootBundle.loadString('assets/config.json');
```

Assets from a package dependency take its name: `AssetImage('icons/heart.png', package: 'my_icons')`, or the path `packages/my_icons/icons/heart.png`.

### Resolution variants

For images, put higher-density versions in `2.0x/`, `3.0x/` (and so on) folders next to the main file, and declare only the main file. Flutter bundles the variants and picks the closest one for the device’s pixel ratio: a device with a ratio of 2.7 gets `3.0x/logo.png`.

### Fonts and icons

Fonts are declared under `flutter: fonts:` and bundled the same way. Flutter also tree shakes icon fonts in release builds: `MaterialIcons-Regular.otf` keeps only the glyphs your Dart code uses. Using an icon you didn’t use before therefore changes the font file in the build. `--no-tree-shake-icons` keeps every glyph, at the cost of a larger app.

### Shaders

Fragment shaders listed under `flutter: shaders:` are compiled when you build and bundled with the assets, then loaded with `FragmentProgram.fromAsset`.

## Where assets end up

At build time, Flutter places your assets in the app’s *asset bundle*:

* **Android**: `assets/flutter_assets/` inside the APK or app bundle.
* **iOS and macOS**: `flutter_assets/` inside `App.framework`.
* **Windows and Linux**: `data/flutter_assets/` next to the executable.

Each bundle also carries an `AssetManifest` listing what’s in it. Files that belong to the native app rather than to Flutter, such as the launcher icon and launch screen (`android/app/src/main/res`, `ios/Runner/Assets.xcassets`), are built into Android resources or the iOS asset catalog instead. See [How Flutter builds your app](/flutter-concepts/how-flutter-builds-your-app/) for the rest of the build output.

## Assets and Code Push

A Shorebird patch replaces your compiled Dart code only. Every file above, from `flutter_assets` to Android resources and the iOS asset catalog, stays as the store release installed it. So:

* **Adding or changing an asset** needs a new store release. A patch that refers to an image the release doesn’t contain fails to load it on users’ devices.
* **Removing an asset** is safe if no code still uses it: the release keeps the file, and the patch just stops using it.
* **Using a new icon** from an icon font changes the tree-shaken font. The release’s font doesn’t have the glyph, so the icon renders incorrectly in the patched app.

`shorebird patch` compares the new build’s assets with the release’s and stops to ask before publishing when assets were added or changed:

```
[WARN] Your app contains asset changes, which will not be included in the patch.
```

What each listed file means, and when it’s safe to continue, is covered in [`Your app contains asset changes` warning when creating a patch](/code-push/troubleshooting/#your-app-contains-asset-changes-warning-when-creating-a-patch).

### Keeping content changeable between releases

Some content changes more often than your store releases. A few patterns keep it updatable:

* **Put text and configuration in Dart code.** Strings generated by Flutter’s [internationalization tooling](https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization) (`gen-l10n`) compile into Dart code, so translation fixes can ship in a patch. So can constants and `--dart-define` values.
* **Draw simple graphics in code.** A `CustomPainter`, a gradient or a widget composition is Dart code; an SVG or PNG file is an asset.
* **Load content that changes often from the network**, with `Image.network` or a caching package, instead of bundling it. The same applies to Lottie or Rive animations, which load from a URL as well as from an asset (see [Flutter Animations](/flutter-concepts/animations/#third-party-vector-animations)).
* **Add assets in a release ahead of the code that uses them**, when you know a feature is coming.
* **Keep every icon glyph** if your patches often start using new Material icons. `--no-tree-shake-icons` is a Flutter flag, so pass it after `--`, to the release and to every patch: `shorebird release android -- --no-tree-shake-icons`.
