bevyengine/bevy
bevy_app
The application-layer crate. Owns the App, the plugin system, the schedule labels every other crate composes against, and the runners that drive the main loop. Almost every other crate in the workspace depends on bevy_app.
Purpose
bevy_app defines the top-level container that composes everything else. It does three things:
- Provides
App,SubApp, and thePlugin/PluginGrouptraits used to compose features. - Defines the canonical schedule labels (
Update,PostUpdate,FixedUpdate, etc.) that the rest of the engine targets. - Provides runners — the loop drivers that call
World::run_schedule(Main)repeatedly, including the headlessScheduleRunnerPluginand the panic / Ctrl-C handlers.
This crate is intentionally small and contains no game logic.
Directory layout
crates/bevy_app/src/
├── app.rs # App + AppExit
├── sub_app.rs # SubApp container
├── plugin.rs # Plugin trait
├── plugin_group.rs # PluginGroup trait + plugin_group! macro
├── main_schedule.rs # Update, PostUpdate, FixedUpdate, …
├── schedule_runner.rs # Headless runner plugin
├── panic_handler.rs # tracing-friendly panic hook
├── terminal_ctrl_c_handler.rs # Catch Ctrl-C → AppExit
├── hierarchy.rs # App helpers for spawning hierarchies
├── propagate.rs # Hierarchy propagation utilities
├── task_pool_plugin.rs # Initializes ComputeTaskPool/AsyncComputeTaskPool/IoTaskPool
├── hotpatch.rs # Optional hot-patching support (behind feature flag)
└── lib.rsKey abstractions
| Type | File | One-line description |
|---|---|---|
App |
crates/bevy_app/src/app.rs |
The root container. Holds sub-apps, plugins, and the runner. |
SubApp |
crates/bevy_app/src/sub_app.rs |
A self-contained world + schedules. Used for the renderer. |
Plugin |
crates/bevy_app/src/plugin.rs |
Trait. build(&self, &mut App) is the unit of feature composition. |
PluginGroup |
crates/bevy_app/src/plugin_group.rs |
Composes related plugins; supports per-element disable/replace. |
AppExit |
crates/bevy_app/src/app.rs |
Event the runner watches for to stop the loop. |
Update etc. |
crates/bevy_app/src/main_schedule.rs |
The standard schedule labels. |
ScheduleRunnerPlugin |
crates/bevy_app/src/schedule_runner.rs |
Headless runner — runs the Main schedule in a loop. |
PanicHandlerPlugin |
crates/bevy_app/src/panic_handler.rs |
Sets a panic hook that emits a tracing::error!. |
TaskPoolPlugin |
crates/bevy_app/src/task_pool_plugin.rs |
Initializes the global ComputeTaskPool/AsyncComputeTaskPool/IoTaskPool. |
How it works
App is mostly a thin wrapper around a default SubApp plus a registry of additional named sub-apps. The render SubApp (added by bevy_render::RenderPlugin) is the canonical example.
graph TD
App --> Main[Main SubApp]
App --> Render[RenderApp SubApp]
App --> Other["… any number of named SubApps"]
Main --> MS[Schedules: Update/PostUpdate/FixedUpdate/…]
Main --> MW[World]
Render --> RS[Schedules: ExtractSchedule/Render]
Render --> RW[World]The runner is a Box<dyn Fn(App) -> AppExit> stored on App. App::run() invokes the runner. Plugins can replace the runner — WinitPlugin does this so the OS event loop becomes the main driver, calling world.run_schedule(Main) once per frame.
Schedule labels are defined as zero-sized types deriving ScheduleLabel. The full list (in execution order on the main schedule):
FirstPreUpdateStateTransitionRunFixedMainLoop(which itself runsFixedFirst → FixedPreUpdate → FixedUpdate → FixedPostUpdate → FixedLastzero or more times)UpdateSpawnScenePostUpdateLast
Plus PreStartup, Startup, PostStartup (each runs exactly once on the first tick).
Plugin composition
Adding a plugin:
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(MyPlugin)
.run();A plugin group is a more powerful unit:
App::new()
.add_plugins(DefaultPlugins.build()
.disable::<AudioPlugin>()
.add_after::<TimePlugin, _>(MyTimePlugin))
.run();The plugin_group! macro in plugin_group.rs generates a PluginGroup impl from a struct + enabled list, including per-feature cfg gates. DefaultPlugins and MinimalPlugins are generated this way (see crates/bevy_internal/src/default_plugins.rs).
Integration points
- Depends on:
bevy_ecs,bevy_reflect,bevy_tasks,bevy_platform,bevy_utils. - Depended on by: Every other engine crate. Adding a feature means writing a
Pluginfrom this crate. - Runner override hook: plugins can call
app.set_runner(...)exactly once.
Entry points for modification
- Adding a new schedule label: define a struct deriving
ScheduleLabelin your plugin and callapp.init_schedule(MyLabel). Look atmain_schedule.rsfor the canonical pattern. - Adding a new SubApp:
app.insert_sub_app(MyAppLabel, SubApp::new()). The render plugin shows how. - Replacing the runner: call
app.set_runner(my_runner)from a plugin. Don't do this lightly — most code paths assume the standard runner. - Adding terminal/Ctrl-C handling: edit
terminal_ctrl_c_handler.rs(Unix/Windows only).
See also
- Architecture for the full App lifecycle picture.
bevy_internalfor theDefaultPluginsdefinition.bevy_ecsfor theWorldandScheduletypesAppwraps.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.