Bevy Version:0.9(outdated!)

As this page is outdated, please refer to Bevy's official migration guides while reading, to cover the differences: 0.9 to 0.10, 0.10 to 0.11, 0.11 to 0.12, 0.12 to 0.13, 0.13 to 0.14.

I apologize for the inconvenience. I will update the page as soon as I find the time.

Load Assets from Files with AssetServer

Relevant official examples: asset_loading.

To load assets from files, use the AssetServer resource.

struct UiFont(Handle<Font>);

fn load_ui_font(
    mut commands: Commands,
    server: Res<AssetServer>
) {
    let handle: Handle<Font> = server.load("font.ttf");

    // we can store the handle in a resource:
    //  - to prevent the asset from being unloaded
    //  - if we want to use it to access the asset later

This queues the asset loading to happen in the background, and return a handle. The asset will take some time to become available. You cannot access the actual data immediately in the same system, but you can use the handle.

You can spawn entities like your 2D sprites, 3D models, and UI, using the handle, even before the asset has loaded. They will just "pop in" later, when the asset becomes ready.

Note that it is OK to call asset_server.load(…) as many times as you want, even if the asset is currently loading, or already loaded. It will just provide you with the same handle. Every time you call it, it will just check the status of the asset, begin loading it if needed, and give you a handle.

Bevy supports loading a variety of asset file formats, and can be extended to support more. The asset loader implementation to use is selected based on the file extension.

Untyped Loading

If you want an untyped handle, you can use asset_server.load_untyped(…) instead.

Untyped loading is possible, because Bevy always detects the file type from the file extension anyway.

Loading Folders

You can also load an entire folder of assets, regardless of how many files are inside, using asset_server.load_folder(…). This gives you a Vec<HandleUntyped> with all the untyped handles.

struct ExtraAssets(Vec<HandleUntyped>);

fn load_extra_assets(
    mut commands: Commands,
    server: Res<AssetServer>,
) {
    if let Ok(handles) = server.load_folder("extra") {

Loading folders is not supported by all I/O backends. Notably, it does not work on WASM/Web.

AssetPath and Labels

The asset path you use to identify an asset from the filesystem is actually a special AssetPath, which consists of the file path + a label. Labels are used in situations where multiple assets are contained in the same file. An example of this are GLTF files, which can contain meshes, scenes, textures, materials, etc.

Asset paths can be created from a string, with the label (if any) attached after a # symbol.

fn load_gltf_things(
    mut commands: Commands,
    server: Res<AssetServer>
) {
    // get a specific mesh
    let my_mesh: Handle<Mesh> = server.load("my_scene.gltf#Mesh0/Primitive0");

    // spawn a whole scene
    let my_scene: Handle<Scene> = server.load("my_scene.gltf#Scene0");
    commands.spawn(SceneBundle {
        scene: my_scene,

See the GLTF page for more info about working with 3D models.

Where are assets loaded from?

The asset server internally relies on an implementation of the AssetIo Rust trait, which is Bevy's way of providing "backends" for fetching data from different types of storage.

Bevy provides its own default built-in I/O backends for each supported platform.

On desktop platforms, it treats asset paths as relative to a folder called assets, that must be placed at one of the following locations:

  • Alongside the game's executable file, for distribution
  • In your Cargo project folder, when running your game using cargo during development
    • This is identified by the CARGO_MANIFEST_DIR environment variable

On the web, it fetches assets using HTTP URLs pointing within an assets folder located alongside the game's .wasm file.

There are unofficial plugins available that provide alternative I/O backend implementations, such as for loading assets from inside archive files (.zip), embedded inside the game executable, using a network protocol, … many other possibilities.