Jesse A. Green / notebook

Bevy Admin Guide

Generated June 2026 from bevyengine/bevy at 457b918

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for engine integrators, technical leads, and architects who need to understand how Bevy is built, how to configure and deploy it, and how to operate and extend it at depth. It covers the workspace architecture, the ECS and rendering internals, the full configuration surface, security considerations, build/deployment targets, performance tuning, and known limitations.

Note

This guide documents the 0.19.0-dev development line (the main branch, crate version 0.19.0-dev). Bevy releases roughly quarterly with breaking changes and official migration guides. Pin a specific version in production and treat each upgrade as a planned migration.


1. Executive Summary

Bevy is a free, open-source, data-driven game engine written in Rust. Its defining characteristics:

Property Detail
Language Rust (edition 2024). MSRV tracks close to the latest stable release.
Architecture A modular Cargo workspace of ~80 bevy_* crates, composed via a plugin system.
Core paradigm Entity Component System (ECS) — data-oriented, automatically parallelized.
Rendering Built on wgpu 29.x (Vulkan / Metal / DX12 / OpenGL / WebGPU / WebGL2).
Math glam 0.32 (SIMD-accelerated), re-exported via bevy_math.
Windowing/Input winit 0.30; gamepad via gilrs; accessibility via accesskit 0.24.
Licensing Dual MIT OR Apache-2.0.
Targets Windows, macOS, Linux, Web (Wasm), Android, iOS, and no_std.

The engine's central design principle is modularity: every feature — including rendering itself — is a plugin gated behind a Cargo feature. Applications compose exactly the subset they need, trading functionality against compile time and binary size.


2. Architecture

2.1 The umbrella crate and sub-crates

The bevy crate is a thin facade. It contains almost no logic of its own; it re-exports the sub-crates as modules and pulls in bevy_internal:

bevy (umbrella facade, #![no_std])
  └── pub use bevy_internal::*;
        ├── DefaultPlugins / MinimalPlugins  (default_plugins.rs)
        ├── prelude                          (re-exports each sub-crate's prelude)
        └── pub use bevy_app as app, bevy_ecs as ecs, bevy_render as render, …

Each module of bevy (except prelude) is published independently on crates.io as bevy_<name>. Consumers may depend on the umbrella crate for convenience or on individual crates for fine-grained control. bevy_internal exists as a separate crate specifically to enable simple dynamic linking (the bevy_dylib crate).

2.2 Crate map

The workspace is organized under crates/. The most significant crates, grouped by concern:

Layer Crates
Foundation bevy_ecs (the ECS), bevy_app (App/Plugin/schedules), bevy_reflect (runtime reflection), bevy_ptr, bevy_platform (platform abstraction, no_std support), bevy_tasks (task pools), bevy_utils, bevy_derive, bevy_macro_utils.
Math & time bevy_math (glam wrapper, curves, primitives, bounding volumes, sampling), bevy_transform, bevy_time.
Assets & scenes bevy_asset (async loading, processing, IO backends), bevy_scene, bevy_world_serialization, bevy_gltf, bevy_image, bevy_mesh, bevy_shader, bevy_material.
Rendering bevy_render (render graph, wgpu integration), bevy_core_pipeline, bevy_pbr (3D PBR), bevy_sprite / bevy_sprite_render (2D), bevy_camera, bevy_light, bevy_anti_alias, bevy_post_process, bevy_gizmos / bevy_gizmos_render, bevy_solari (experimental raytracing).
Windowing & input bevy_window, bevy_winit, bevy_input, bevy_input_focus, bevy_gilrs, bevy_a11y, bevy_clipboard.
UI bevy_ui, bevy_ui_render, bevy_ui_widgets, bevy_feathers, bevy_text.
App services bevy_audio, bevy_animation, bevy_state, bevy_picking, bevy_log, bevy_diagnostic, bevy_dev_tools, bevy_remote, bevy_settings.

Note

This separation is deliberate: a headless server can depend on bevy_app + bevy_ecs + bevy_time without ever pulling in bevy_render or wgpu. The default_app and default_platform feature collections exist to make this composition ergonomic.

2.3 The App and SubApp model

App is the top-level container. Internally it holds a SubApps collection: one "main" SubApp plus any number of labeled secondary sub-apps. Each SubApp owns its own World, schedules, and plugin registry. App's methods operate on the main sub-app unless you explicitly target another via sub_app_mut(label).

The renderer uses this: bevy_render runs a separate Render sub-app with its own world, and each frame "extracts" data from the main world into the render world. This is what allows pipelined rendering (the render world processing frame N while the main world simulates frame N+1).

App
 ├── SubApps.main      → World (game state) + schedules
 └── SubApps[Render]   → World (GPU-facing state) + render schedules
                          (added by RenderPlugin; runs on its own thread when
                           PipelinedRenderingPlugin is active)

2.4 The plugin lifecycle

Plugins are added via App::add_plugins. Each plugin progresses through a four-phase lifecycle, tracked by PluginsState (Adding → Ready → Finished → Cleaned):

Phase Method Purpose
build Plugin::build(&self, app) Register systems, resources, types. Runs immediately on add_plugins.
ready Plugin::ready(&self, app) -> bool Poll until asynchronous setup (e.g. GPU init) completes.
finish Plugin::finish(&self, app) Final setup once all plugins are ready.
cleanup Plugin::cleanup(&self, app) One-time teardown of build-time scaffolding.

App::run drives this: it blocks while any plugin is in Adding, ticking the global task pools, then calls finish and cleanup before invoking the runner. Adding plugins after finish/cleanup panics. Duplicate plugins (by name) are rejected with AppError::DuplicatePlugin unless the plugin opts out of uniqueness via is_unique() == false.

2.5 DefaultPlugins composition (build order)

DefaultPlugins is defined with the plugin_group! macro in crates/bevy_internal/src/default_plugins.rs. Build order matters and is encoded explicitly. The sequence (each entry gated by its feature flag):

PanicHandlerPlugin → LogPlugin → TaskPoolPlugin → FrameCountPlugin → TimePlugin
→ TransformPlugin → DiagnosticsPlugin → InputPlugin → InputFocusPlugin/InputDispatchPlugin
→ [ScheduleRunnerPlugin if no window] / WindowPlugin + AccessibilityPlugin
→ TerminalCtrlCHandlerPlugin → WebAssetPlugin (if http/https) → AssetPlugin
→ WorldSerializationPlugin → ScenePlugin → WinitPlugin → [DlssInitPlugin]
→ RenderPlugin → ImagePlugin → MeshPlugin → CameraPlugin → LightPlugin
→ PipelinedRenderingPlugin → CorePipelinePlugin → PostProcessPlugin → AntiAliasPlugin
→ SpritePlugin → SpriteRenderPlugin → ClipboardPlugin → TextPlugin → UiPlugin
→ UiRenderPlugin → GltfPlugin → PbrPlugin → AudioPlugin → GilrsPlugin
→ AnimationPlugin → GizmoPlugin → GizmoRenderPlugin → StatesPlugin
→ [CiTestingPlugin] → [RenderDebugOverlayPlugin] → [HotPatchPlugin]
→ UiWidgetsPlugins → DefaultPickingPlugins → IgnoreAmbiguitiesPlugin

Ordering constraints worth noting (encoded in source comments):

  • WebAssetPlugin loads before AssetPlugin to register HTTP/HTTPS asset sources.
  • WinitPlugin loads after AssetPlugin because custom cursors are assets.
  • ImagePlugin loads after RenderPlugin so it knows the renderer's supported compressed texture formats.
  • IgnoreAmbiguitiesPlugin runs last to suppress known, benign system-ordering ambiguities between plugin pairs (e.g. bevy_ui vs bevy_animation both touching Transform in PostUpdate).

MinimalPlugins is the bare runtime: TaskPoolPlugin → FrameCountPlugin → TimePlugin → ScheduleRunnerPlugin.

2.6 The schedule pipeline

The Main schedule (added by MainSchedulePlugin) runs a fixed ordered list of sub-schedules each frame. The full pipeline:

Startup (once):  PreStartup → Startup → PostStartup

Per frame:       First
                 PreUpdate
                 RunFixedMainLoop ──► (FixedFirst → FixedPreUpdate → FixedUpdate
                                        → FixedPostUpdate → FixedLast)  × 0..N
                 Update
                 SpawnScene
                 PostUpdate
                 Last

RunFixedMainLoop consumes accumulated real time in fixed-size steps (Time<Fixed>, default 64 Hz), running the FixedMain schedule zero or more times to catch up. This decouples deterministic simulation from variable render frame rate.

2.7 ECS internals

bevy_ecs is the engine's foundation. Its storage and execution model:

Concept Implementation
Entity A 32-bit index + generation. Lightweight handle; owns no data.
Component Data with #[derive(Component)]. Stored either in Table (dense, default — cache-friendly for iteration) or SparseSet (fast add/remove) storage, selectable via #[component(storage = "...")].
Archetype The set of entities sharing an identical component set. The world has one archetype per unique component combination; archetypes are created but never freed.
Table The columnar backing store. Multiple archetypes may share a table; they differ only by their sparse-set components.
Query A typed view over matching archetypes. Access (&/&mut) is analyzed for conflicts so non-overlapping systems parallelize.
Edges Cached archetype graph transitions for bundle insert/remove, avoiding recomputation when entities change shape.
Schedule executor Runs a schedule's systems, parallelizing those with disjoint access. ApplyDeferred flushes queued Commands at sync points.

Modules within bevy_ecs: archetype, bundle, change_detection, component, entity, entity_disabling, error, event, hierarchy, message, observer, query, reflect, relationship, resource, schedule, spawn, storage, system, world, lifecycle, name, template, traversal.

Important

Archetypes and tables are never garbage-collected — they persist until the World is dropped. Code that rapidly creates and destroys entities with many distinct component combinations can grow archetype/table count unbounded. Prefer reusing entities or marker-component toggling over churning archetypes.

2.8 Communication models

Bevy offers three distinct mechanisms, each with different delivery semantics:

Mechanism Delivery Use for
Messages (Message, MessageReader/MessageWriter) Double-buffered queue, ~2-frame lifetime, polled Decoupled, batch-processed, many-to-many communication.
Observers (Event/EntityEvent, On<…>, add_observer) Immediate, synchronous, targeted Reactive, must-handle, one-off responses.
Lifecycle events (Add/Insert/Remove/Despawn, RemovedComponents<T>) Engine-fired on structural change Reacting to component/entity lifecycle.

The change-detection system (Added<T>, Changed<T>, Ref<T>, DetectChanges) is a fourth, pull-based reactive primitive built on per-component change ticks.

2.9 Rendering architecture

bevy_render integrates wgpu and defines a render graph — a DAG of render nodes (passes). Each frame the renderer:

  1. Extract — copies needed data from the main world into the render sub-app's world.
  2. Prepare — uploads GPU resources (buffers, textures, bind groups).
  3. Queue — assigns entities to render phases.
  4. Sort & Render — executes the render graph, encoding draw commands.

bevy_core_pipeline provides the 2D/3D core passes and tonemapping; bevy_pbr adds physically-based 3D shading, clustered lighting, shadows, prepass, deferred shading, SSAO/SSR, atmosphere, and (experimentally) meshlets and Solari raytracing. Shaders are written in WGSL and compiled via naga.


3. System Requirements

Concern Requirement
Rust Recent stable (MSRV ≈ latest stable). Edition 2024 support required.
GPU A backend supported by wgpu 29: Vulkan (Linux/Windows/Android), Metal (macOS/iOS), DirectX 12 (Windows), OpenGL/GLES (fallback), WebGPU/WebGL2 (web).
Linux display X11 and/or Wayland (x11, wayland features; both default). Vulkan loader and drivers installed.
Web A browser with WebGL2 or WebGPU; the wasm32-unknown-unknown target.
Android NDK/SDK; API level 33 in examples; minimum API 26 if bevy_audio is used.
Disk/RAM (build) A full-engine debug build is heavy; budget several GB of RAM and disk for target/.

4. Configuration Mastery

Bevy is configured almost entirely in code, by customizing the plugins in DefaultPlugins via .set(...), plus a small number of environment variables. There is no central config file.

4.1 Window configuration (WindowPlugin)

DefaultPlugins.set(WindowPlugin {
    primary_window: Some(Window {
        title: "My Game".into(),
        resolution: (1920.0, 1080.0).into(),
        present_mode: bevy::window::PresentMode::AutoVsync,
        mode: bevy::window::WindowMode::Windowed,
        resizable: true,
        ..default()
    }),
    // Quit the app when the last window closes:
    exit_condition: bevy::window::ExitCondition::OnAllClosed,
    close_when_requested: true,
    ..default()
})
Field Controls
primary_window The initial window's properties (or None for headless).
present_mode VSync behavior (AutoVsync, AutoNoVsync, Fifo, Immediate, Mailbox).
mode Windowed / borderless / fullscreen.
exit_condition When the app should exit relative to window closure.

4.2 Renderer configuration (RenderPlugin / WgpuSettings)

The renderer is configured through RenderPlugin { render_creation: WgpuSettings { … } } (defined in crates/bevy_render/src/settings.rs):

use bevy::render::settings::{Backends, WgpuSettings, RenderCreation, PowerPreference};
use bevy::render::RenderPlugin;

DefaultPlugins.set(RenderPlugin {
    render_creation: RenderCreation::Automatic(WgpuSettings {
        backends: Some(Backends::VULKAN),
        power_preference: PowerPreference::HighPerformance,
        ..default()
    }),
    ..default()
})
Setting Effect
backends Restrict to specific wgpu backends (VULKAN, METAL, DX12, GL, BROWSER_WEBGPU).
power_preference HighPerformance (discrete GPU) vs LowPower (integrated).
features / limits Required wgpu Features and Limits.
priority Read from the WGPU_SETTINGS_PRIO environment variable to bias compatibility vs. functionality.

Tip

wgpu also honors its own environment variables independent of Bevy: WGPU_BACKEND forces a backend (vulkan, metal, dx12, gl), and WGPU_POWER_PREF sets the power preference. These are useful for debugging GPU-selection issues without recompiling.

4.3 Logging configuration (LogPlugin)

bevy_log integrates with the tracing ecosystem.

use bevy::log::LogPlugin;

DefaultPlugins.set(LogPlugin {
    level: bevy::log::Level::INFO,
    filter: "wgpu=error,bevy_render=info,my_game=debug".into(),
    ..default()
})
Field Controls
level The minimum log level.
filter A per-target RUST_LOG-style filter string.
custom_layer Hook to add your own tracing layers.

Environment variable: TRACE_CHROME (read in crates/bevy_log/src/lib.rs) — when the trace_chrome feature is enabled, controls the output path of the Chrome-format trace file. The RUST_LOG environment variable also overrides the filter at runtime.

4.4 Asset configuration (AssetPlugin)

use bevy::asset::AssetPlugin;

DefaultPlugins.set(AssetPlugin {
    file_path: "assets".into(),
    watch_for_changes_override: Some(true), // hot-reload (needs file_watcher feature)
    ..default()
})

bevy_asset supports multiple IO backends (file, embedded, web/HTTP) and an optional asset processor (the asset_processor feature) that transforms source assets into optimized runtime assets. Web asset sources are enabled by the http / https features and the WebAssetPlugin.

4.5 Task pools (TaskPoolPlugin)

TaskPoolPlugin configures the compute/async-compute/IO thread pools. By default it sizes them based on available CPU cores. Override via TaskPoolOptions if you need to reserve cores. The multi_threaded feature (default on) enables parallel execution; disabling it forces all engine work onto one thread (useful for Wasm and debugging).

4.6 Environment variable summary

Variable Read by Effect
RUST_LOG bevy_log (tracing) Override log filter at runtime.
TRACE_CHROME bevy_log (trace_chrome feature) Chrome trace output path.
WGPU_SETTINGS_PRIO bevy_render settings Bias wgpu settings priority (compatibility/functionality).
WGPU_BACKEND wgpu Force a specific GPU backend.
WGPU_POWER_PREF wgpu Force power preference.
CARGO_MANIFEST_DIR build tooling (build-easefunction-graphs) Build-time asset path resolution.
GITHUB_ACTIONS CI example harness Detect CI for automated example testing.

5. Security Analysis

Bevy is a client-side game engine, but several subsystems have real security implications, especially for networked or web-deployed games.

5.1 Remote asset loading (HTTP/HTTPS)

The http and https features enable WebAssetPlugin, letting the engine download assets from URLs at runtime.

Caution

Loading assets over the network executes parsing/decoding code (image, glTF, audio decoders) on untrusted, attacker-controllable data. The feature documentation explicitly warns of security implications. Only enable http/https when you control the asset sources, validate URLs, and prefer https over http. The web_asset_cache feature caches downloads on disk but never invalidates entries — a poisoned cache entry persists.

5.2 The Bevy Remote Protocol (bevy_remote)

bevy_remote (the bevy_remote feature) exposes the Bevy Remote Protocol — a remote interface for inspecting and mutating a running app's world (used by editors and tooling).

Warning

The remote protocol grants powerful read/write access to the ECS world. Treat any open remote port as an administrative interface: bind it to localhost, never expose it on untrusted networks, and disable the feature entirely in shipped builds unless required.

5.3 Deserialization (scenes & reflection)

bevy_scene and bevy_world_serialization deserialize world state via bevy_reflect and serde. Loading a scene file instantiates components by reflected type.

Important

Treat scene/world files as code-equivalent trust boundaries. Only load scene files from trusted sources; a malicious scene can spawn arbitrary registered components and resources. Validate or sandbox any user-supplied scene content.

5.4 Native code and unsafe

bevy_ecs uses unsafe deliberately for performance (storage access, parallel execution). bevy_internal and the umbrella crate set #![forbid(unsafe_code)], isolating unsafety to the lower-level crates where it is audited (the workspace lints enforce undocumented_unsafe_blocks = "warn" and unsafe_op_in_unsafe_fn = "warn"). Optional C-backed dependencies (zstd_c, statically-linked-dxc) introduce native code; the pure-Rust alternatives (zstd_rust) are the safe defaults.

5.5 Dependency surface

The engine pulls in a large dependency tree (wgpu, winit, glam, image codecs, audio codecs, accesskit). Audit transitive dependencies with cargo audit / cargo deny in CI, and minimize the feature set to shrink the attack surface. Disabling image/audio format features you don't use removes their decoders entirely.


6. Build, Packaging & Deployment

6.1 Profiles and optimization

# Optimize dependencies even in dev builds (big runtime win, small build cost):
[profile.dev.package."*"]
opt-level = 3

[profile.dev]
opt-level = 1

# A tuned release profile:
[profile.release]
lto = "thin"
codegen-units = 1
Build Command
Dev cargo run
Release cargo run --release / cargo build --release
Fast iteration cargo run --features bevy/dynamic_linking

Caution

dynamic_linking must be disabled for shipped builds — it requires the Bevy shared library at runtime and is unsupported on Wasm.

6.2 Desktop packaging

Ship the executable and the assets/ directory (the AssetServer resolves paths relative to it). On Linux, ensure end users have Vulkan drivers. Consider cargo bundling tools for .app/.msi/AppImage packaging.

6.3 Web (WebAssembly)

rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
# then wasm-bindgen / trunk / wasm-server-runner to produce JS glue and serve

Pick exactly one web backend:

Feature Trade-off
webgl2 Broadest browser support; no compute shaders; some advanced effects unavailable.
webgpu Best performance and full feature set; narrower browser support. Overrides webgl2 when both are set.

The web feature enables browser API access; the bevy_dylib-style dynamic linking is unavailable on Wasm. Consider multi_threaded carefully — threading support on the web requires cross-origin isolation headers.

6.4 Mobile

Platform Notes
Android android-game-activity (default, GameActivity) or android-native-activity (legacy, for cargo-apk). Targets: aarch64-linux-android, armv7-linux-androideabi. Examples target API 33; bevy_audio requires API ≥ 26. bevy_android provides the entry glue.
iOS An Xcode project (examples/mobile) drives a static/cdylib build. App::run never returns on iOS (event-loop-owned).

6.5 Headless / server deployment

For dedicated servers and CLI tools, avoid the renderer entirely:

bevy = { version = "0.18", default-features = false, features = ["default_app"] }
use bevy::prelude::*;
use bevy::app::ScheduleRunnerPlugin;
use std::time::Duration;

App::new()
    .add_plugins(MinimalPlugins.set(
        ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1.0 / 60.0))
    ))
    .run();

Note

Without a fixed run_loop duration, ScheduleRunnerPlugin spins as fast as possible and saturates a CPU core. Always cap the tick rate for servers.


7. Operations

7.1 Diagnostics

bevy_diagnostic (always included) collects runtime metrics. Add the built-in plugins to surface them:

use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin};

app.add_plugins((FrameTimeDiagnosticsPlugin::default(), LogDiagnosticsPlugin::default()));

This logs FPS, frame time, and entity counts. The sysinfo_plugin feature adds CPU/memory system diagnostics. EntityCountDiagnosticsPlugin reports live entity counts — watch this to catch archetype/entity leaks.

7.2 Tracing and profiling

Feature Tool
trace Base tracing spans throughout the engine.
trace_tracy Stream spans to the Tracy profiler (frame-by-frame timeline).
trace_tracy_memory Tracy with allocation tracking.
trace_chrome Emit a Chrome-tracing JSON file (path via TRACE_CHROME).
detailed_trace Compile-in extra-fine spans (off by default; expensive).

7.3 Developer tools

The dev feature collection (debug + bevy_dev_tools + file_watcher) enables hot-reloading and debug overlays. bevy_dev_tools includes CI testing harnesses, a frame-time graph, schedule inspection (schedule_data feature), and (with bevy_pbr) a render debug overlay. The bevy_debug_stepping feature enables stepping execution through systems one at a time.

Warning

The dev collection and bevy_dev_tools are for development only. Never enable them in shipped builds — they add overhead and expose internals.

7.4 Logs

Logging is driven by tracing. Control verbosity with the LogPlugin filter or the RUST_LOG environment variable. A common production filter quiets noisy subsystems: RUST_LOG="wgpu=error,naga=error,info".


8. Performance Tuning

Lever Guidance
Feature trimming Disable unused Cargo features (image/audio formats, experimental renderers). Fewer features = faster builds, smaller binaries, less surface.
multi_threaded Keep enabled for parallel system execution on native targets.
Change detection Use Changed<T>/Added<T> to avoid recomputing unchanged data every frame.
Query design Prefer Table storage (default) for components iterated in hot loops; SparseSet for components frequently added/removed.
Fixed timestep Put heavy simulation in FixedUpdate so it runs at a bounded rate, not per render frame.
System ordering Avoid over-constraining order; unordered systems parallelize. Only add .before/.after/.chain where correctness requires.
Batching / instancing The PBR/sprite renderers automatically batch and GPU-instance compatible draws. Stress examples (bistro, caldera_hotel) expose flags to toggle frustum/occlusion culling, automatic batching, and indirect drawing for profiling.
Pipelined rendering PipelinedRenderingPlugin (auto-enabled on native + multi_threaded) overlaps the render world with the next simulation frame.
Texture compression Use compressed formats (KTX2 with zstd_rust/zstd_c, Basis Universal, BCn) to cut VRAM and load time.
Benchmarks The benches crate uses Criterion; run with `cargo bench -p benches --bench <ecs

Tip

The renderer auto-batches and auto-instances by default. If profiling a draw-call bottleneck, the large-scene examples document --no-automatic-batching, --no-frustum-culling, --no-indirect-drawing, and --no-cpu-culling flags to isolate which stage is the cost.


9. Repository Structure (for contributors)

bevy/
├── crates/              ~80 bevy_* sub-crates (the engine)
├── src/lib.rs           Umbrella facade: pub use bevy_internal::*
├── examples/            Hundreds of runnable examples, grouped by topic
│   ├── 2d/ 3d/ ui/ ecs/ shader/ animation/ audio/ …
│   ├── mobile/          Android (GameActivity & native) + iOS projects
│   ├── stress_tests/    Performance stress scenarios
│   └── large_scenes/    bistro, caldera_hotel, bevy_city (real-world scenes)
├── benches/             Criterion benchmarks (ecs, render, reflect, …)
├── tools/               Internal tooling
│   ├── ci/              The CI command runner (cargo run -p ci)
│   ├── build-templated-pages/   Generates docs/cargo_features.md
│   ├── build-wasm-example/      Wasm example builder
│   └── example-showcase/        Example catalog/screenshot generator
├── tests/ tests-integration/    Integration tests
├── errors/              Error code documentation
├── docs/                cargo_features.md and other docs
└── assets/              Example assets (not shipped in published crates)

9.1 Contributing workflow

  • CI is orchestrated by tools/ci (cargo run -p ci), which runs formatting, clippy, tests, doc checks, and compile-fail tests on stable Rust.
  • Compile-fail tests (crates/*/compile_fail) assert exact compiler errors for macros; they live outside the workspace to avoid breaking crater.
  • Workspace lints are strict: undocumented_unsafe_blocks, unsafe_op_in_unsafe_fn, allow_attributes_without_reason, std_instead_of_core (for no_std crates), and many clippy pedantic lints are set to warn.
  • no_std support: foundation crates compile without std. CI checks against x86_64-unknown-none, wasm32v1-none, and thumbv6m-none-eabi targets using libm + critical-section.
  • RFCs for large architectural changes go to the bevyengine/rfcs repository.

10. Quick Reference

10.1 App builder methods

Method Purpose
App::new() / App::empty() Full / minimal app scaffolding.
add_plugins(p) Install plugin(s) or group(s).
add_systems(schedule, sys) Add systems to a schedule.
configure_sets(schedule, sets) Order/gate system sets.
insert_resource(v) / init_resource::<T>() Provide resources.
add_message::<M>() Enable a message type.
add_observer(obs) Register a global observer.
register_type::<T>() Register a reflected type.
register_required_components::<T, R>() Declare R required by T.
set_runner(f) Replace the main-loop runner.
run() Build and start the app.

10.2 Schedules

Group Schedules
Startup PreStartup, Startup, PostStartup
Main (per frame) First, PreUpdate, RunFixedMainLoop, Update, SpawnScene, PostUpdate, Last
Fixed (in RunFixedMainLoop) FixedFirst, FixedPreUpdate, FixedUpdate, FixedPostUpdate, FixedLast

10.3 Feature profiles & collections

Tier Examples
Profiles default, 2d, 3d, ui
Collections dev, audio, audio-all-formats, scene, picking, default_app, default_platform, common_api, default_no_std
Render backends webgl2, webgpu, raw_vulkan_init
Platform x11, wayland, android-game-activity, std, libm, critical-section

10.4 Key environment variables

RUST_LOG, TRACE_CHROME, WGPU_SETTINGS_PRIO, WGPU_BACKEND, WGPU_POWER_PREF.


11. Known Limitations & Improvement Areas

Drawn from the engine's own warnings, feature documentation, and the community issue tracker at the documented commit.

11.1 Engine-level caveats

  • Pre-1.0, breaking releases — the API changes roughly quarterly; the README explicitly warns important features are still missing and documentation is sparse.
  • Archetypes/tables never freed — high-churn entity shapes can grow memory unbounded (§2.7).
  • MSRV churn — tracks latest stable Rust closely; older toolchains are unsupported.
  • WebGL2 limits — no compute shaders; several rendering features are WebGPU-only.
  • web_asset_cache never invalidates — cached downloads persist indefinitely (§5.1).
  • Experimental subsystems — bevy_solari (raytracing), meshlet, dlss, experimental_pbr_pcss, and ghost UI nodes are explicitly experimental and may change or carry GPU-compatibility risk.

11.2 Community-reported issues (at commit 457b918)

Issue Status Summary
#24525 Open bevy_dev_tools didn't receive a release candidate.
#24521 Open Docs for bevy::asset::io::android are not generated.
#19625 Open objc2 framework panics on a macOS 26 developer beta.
#24508 Open MouseScrollUnit handling is inconsistent — input-scaling caveat for scroll.
#24517 Open AtmosphereEnvironmentMapLight / GeneratedEnvironmentMapLight are very slow — a performance watch item.
#24510 Open Re-enable the std_instead_of_core lint (no_std hygiene).
#24483 Open bevy_extract tracking (planned extract-stage refactor).
#24356 Closed FeathersNumberInput failed when spawned in Update — fixed.
#24346 Closed "CommandQueue has un-applied commands" on delayed-command exit — fixed.

Note

Issue counts are a point-in-time snapshot. The live tracker is the authoritative source: https://github.com/bevyengine/bevy/issues.

11.3 Recommendations for integrators

  • Pin and plan migrations. Lock to a published version and schedule upgrades around the quarterly release + migration guide cadence.
  • Trim features aggressively. Start from default-features = false and a profile (2d/3d/default_app), adding only what you need.
  • Gate dev/remote features out of release builds. Ensure bevy_dev_tools, dev, and bevy_remote are absent from shipped binaries.
  • Treat asset/scene/network inputs as untrusted. Validate sources; prefer pure-Rust decoders; keep http off unless required.
  • Add diagnostics early. Wire up FrameTimeDiagnosticsPlugin and entity-count diagnostics from day one to catch leaks and regressions.