The App

Relevant official examples: All of them ;)

In particular, check out the complete game examples: alien_cake_addict, breakout.


To enter the Bevy runtime, you need to configure an App. The app is how you define the structure of all the things that make up your project: plugins, systems (and their configuration/metadata: run conditions, ordering, sets), event types, states, schedules

You typically create your App in your project's main function. However, you don't have to add everything from there. If you want to add things to your app from multiple places (like other Rust files or crates), use plugins. As your project grows, you will need to do that to keep everything organized.

fn main() {
    App::new()
        // Bevy itself:
        .add_plugins(DefaultPlugins)

        // Plugins from our game/project:
        .add_plugins(ui::MyUiPlugin)

        // events:
        .add_event::<LevelUpEvent>()

        // systems to run once at startup:
        .add_systems(Startup, spawn_things)

        // systems to run each frame:
        .add_systems(Update, (
            camera_follow_player,
            debug_levelups,
            debug_stats_change,
        ))
        // ...

        // launch the app!
        .run();
}

Note: use tuples with add_systems/add_plugins/configure_sets to add multiple things at once.

Component types do not need to be registered.

Schedules cannot (yet) be modified at runtime; all systems you want to run must be added/configured in the App ahead of time. You can control individual systems using run conditions. You can also dynamically enable/disable entire schedules using the MainScheduleOrder resource.

Builtin Bevy Functionality

The Bevy game engine's own functionality is represented as a plugin group. Every typical Bevy app must first add it, using either:

Setting up data

Normally, you can set up your data from systems. Use Commands from regular systems, or use exclusive systems to get full World access.

Add your setup systems to the Startup schedule for things you want to initialize at launch, or use state enter/exit systems to do things when transitioning between menus, game modes, levels, etc.

However, you can also initialize data directly from the app builder. This is common for resources, if they need to be present at all times. You can also get direct World access.

// Create (or overwrite) resource with specific value
app.insert_resource(StartingLevel(3));

// Ensure resource exists; if not, create it
// (using `Default` or `FromWorld`)
app.init_resource::<MyFancyResource>();

// We can also access/manipulate the World directly
// (in this example, to spawn an entity, but you can do anything)
app.world_mut().spawn(SomeBundle::default());

Quitting the App

To cleanly shut down bevy, send an AppExit event from any system:

use bevy::app::AppExit;

fn exit_system(mut exit: EventWriter<AppExit>) {
    exit.send(AppExit::Success);
}

In a real app, you could do this from various places, such as a handler for an "Exit" button in your main menu, etc.

You can specify the exit code to return to the OS. If Bevy receives multiple AppExit events, success will only be returned if all of them report success. If some report an error, the last event will determine the actual exit code of the process.