skip to content

Asset Declaration

Assets are listed under flutter: assets: in pubspec and read through rootBundle or DefaultAssetBundle with loadString or load. Interviewers check variant resolution and package asset paths.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

6

In Flutter, how do you bundle offline JSON question packs and sound files with an app and read them at runtime?

level: juniorimportance: must knowfreq 64%

answer

  1. flutter: then assets: in pubspec.yaml
  2. trailing slash = one directory level
  3. the declared path is the key
  4. rootBundle.loadString returns a Future
  5. build error vs runtime error

basics

~20 s

List the files or directories under flutter: assets: in pubspec.yaml, which copies them into the app's asset bundle, then read them by their declared path: rootBundle.loadString for text such as JSON, rootBundle.load for bytes such as sounds.

solid answer

~40 s

Assets are declared in `pubspec.yaml` under `flutter:` then `assets:`, each entry a path relative to the pubspec. A file path adds that file; a path ending in `/` adds the files *directly* in that directory, so each subdirectory needs its own entry. At build time the `flutter` tool copies them into the asset bundle, and at runtime you read them by the same path used as a key: `rootBundle.loadString('assets/questions/history.json')` returns a `Future<String>`, and `rootBundle.load(...)` returns `Future<ByteData>` for binary files like sounds. A declared file that is missing fails the build with `No file or variants found`; loading an undeclared key fails at runtime with `Unable to load asset`.

code

yaml · 6 lines
yaml
flutter:
  uses-material-design: true
  assets:
    - assets/questions/
    - assets/sounds/
    - assets/sounds/effects/

go deeper

for a junior

Know the pubspec syntax, that a trailing slash adds one directory level, and that rootBundle.loadString and load read files by their declared path.

for a middle

Explain the build step that copies files into the asset bundle, the difference between build-time and runtime errors, and why reads are asynchronous.

for a senior

Organise assets so large packs load lazily and declarations stay in step with the folders, and use AssetManifest instead of hard-coded lists.

for a principal

Decide which content ships in the binary as assets and which is downloaded later, weighing offline play against app size and update speed.

## What an asset is An **asset** is a file that ships inside the app and can be read at runtime: JSON data, configuration, images, audio, shaders. Unlike a file in the device's documents directory, it is read-only and identical on every install. A trivia game that must work offline is a typical case: its question packs are JSON files, and its "correct" and "wrong" sounds are audio files, all bundled with the build. ## Declaring assets in pubspec.yaml Assets are listed in the app's `pubspec.yaml`, under the `flutter:` section: ```yaml flutter: uses-material-design: true assets: - assets/questions/ - assets/sounds/ - assets/sounds/effects/ - assets/credits.txt ``` The rules the `flutter` tool applies: - Each entry is a path **relative to `pubspec.yaml`**. The folder name `assets` is a convention, not a requirement. - An entry ending in **`/`** includes every file **directly** in that directory. Subdirectories are **not** included, which is why `assets/sounds/effects/` needs its own line. (Resolution-aware image variants such as `2.0x/` folders are the one exception.) - An entry without a trailing slash names one file. - The order of entries does not matter. - **Indentation matters.** `assets:` must sit two spaces under `flutter:`; a mis-indented list is a common cause of the error `unable to find directory entry in pubspec.yaml`. An entry can also be a map with a `path:` key plus extra keys such as `transformers:` or `platforms:`, for build-time processing or per-platform bundling. ## How the files reach the app 1. On `flutter run` or `flutter build`, the tool reads the `assets:` list and copies each matching file into the **asset bundle**, a special archive packaged with the app. 2. If a declared file does not exist, the tool reports `No file or variants found for` that asset. 3. At runtime, code asks an `AssetBundle` for a **key**, which is the declared path, such as `assets/questions/history.json`. Keys match exactly, including case. ## Reading assets at runtime `package:flutter/services.dart` exposes **`rootBundle`**, the bundle built with the app: | Call | Returns | Typical use | |---|---|---| | `rootBundle.loadString(key)` | `Future<String>` (UTF-8) | JSON question packs, text | | `rootBundle.load(key)` | `Future<ByteData>` | sounds, binary data | | `rootBundle.loadStructuredData(key, parser)` | `Future<T>` | text parsed once into a model | Inside widgets, `DefaultAssetBundle.of(context)` is preferred, because it lets an ancestor substitute another bundle; it falls back to `rootBundle`. Images normally go through `Image.asset`, which resolves the bundle and resolution variants for you. Every call is asynchronous, so start the load once, in a repository or in `initState`, rather than in `build()`. Turning the JSON string into Dart objects is a separate step handled by `dart:convert` or generated models. ## Bundling only for some platforms Since Flutter 3.41 an entry can carry a `platforms:` list, so a large asset ships only where it is used. Valid values are `android`, `ios`, `web`, `linux`, `macos` and `windows`: ```yaml flutter: assets: - path: assets/sounds/desktop_ambience/ platforms: - macos - windows - linux ``` A phone build then leaves those files out entirely, and code that might run on every platform must not assume the asset exists everywhere. Platform code can read bundled assets too, through `AssetManager` on Android and `NSBundle` on iOS, which matters when a native plugin needs the same sound file. ## Two different failures | Symptom | Cause | |---|---| | Build prints `No file or variants found for ...` | a declared file is missing or misspelled on disk | | Build prints `unable to find directory entry in pubspec.yaml` | a declared directory is missing, often from bad indentation | | Runtime `Unable to load asset: "..."` | the key was never declared, or it differs from the declared path | ## Common mistakes - Expecting a directory entry to pull in its subfolders. - Loading `questions/history.json` when the declared path is `assets/questions/history.json`. - Using `dart:io` `File('assets/...')`: bundled assets are not ordinary files on the device, so read them through an `AssetBundle`. - Calling `rootBundle` in `main()` before `WidgetsFlutterBinding.ensureInitialized()`.

  • Why can't the app open a bundled question pack with File('assets/questions/history.json')?
    Bundled assets live inside the app package, not as plain files at that path on the device, so `dart:io` cannot open them by their pubspec path. Read them through an `AssetBundle` (`rootBundle` or `DefaultAssetBundle.of(context)`), which knows how to fetch them on every platform, including the web.
  • How can the app list every bundled question pack without hard-coding file names?
    Load the asset manifest with `AssetManifest.loadFromAssetBundle(rootBundle)` and call `listAssets()`, then filter keys that start with `assets/questions/`. Do not read `AssetManifest.json`: it was an undocumented detail, and current Flutter no longer generates it.

saying these in an interview costs you the question

  • An entry like assets/sounds/ also includes every subdirectory under it.
  • Any file in the project folder can be loaded without declaring it.
  • The asset key is just the file name, without its folder path.
  • Bundled assets can be opened with dart:io File using their pubspec path.
  • The order of entries under assets: changes which file wins.
open as a page

In Flutter, how are 2.0x and 3.0x image asset variants chosen for a device, and what must pubspec.yaml declare?

level: middleimportance: must knowfreq 46%

basics

~20 s

Put higher-resolution copies in sibling folders such as 2.0x/ and 3.0x/ and declare only the main asset or its directory; Flutter bundles the variants, and AssetImage picks the one closest to the device pixel ratio, rendering it at the main asset's logical size.

open as a page

In Flutter, what do AssetBundle's load, loadString and loadStructuredData return, and which of their results does rootBundle cache?

level: middleimportance: should knowfreq 30%

basics

~20 s

load returns ByteData and is never cached; loadString returns a UTF-8 String that rootBundle caches for the bundle's lifetime unless cache: false; loadStructuredData runs your parser once per key and caches the parsed result, but not failures.

open as a page

In Flutter, how do you declare and load assets that live in a package, such as a shared trivia-content package?

level: middleimportance: should knowfreq 28%

basics

~20 s

A package declares its assets in its own pubspec.yaml, and they are bundled into every app that depends on it under the key packages/<package>/<path>. Load them with that full key, or pass package: to AssetImage or Image.asset.

open as a page

In Flutter, what is the difference between rootBundle and DefaultAssetBundle.of(context), and when would you use each?

level: middleimportance: should knowfreq 36%

basics

~20 s

rootBundle is the global bundle built with the app. DefaultAssetBundle.of(context) returns the bundle provided by the nearest DefaultAssetBundle ancestor, or rootBundle when there is none, so widgets using it can be given a different bundle for tests, localization or downloaded content.

open as a page

In Flutter, what do asset transformers declared in pubspec.yaml do, and how would you add one to shrink bundled JSON question packs?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

An asset transformer is a Dart command-line package the flutter tool runs on an asset while bundling it, writing a transformed file under the same key. Declare it per asset with path: and transformers: in pubspec.yaml, and add the package as a dev dependency.

open as a page