bevyengine/bevy
Component
A component is a piece of data attached to an entity. Components are how Bevy describes what an entity is: a thing with Position and Velocity is a moving object; add Health and it's a destructible object; add Sprite and it's a sprite.
Defining a component
use bevy::prelude::*;
#[derive(Component)]
struct Health(u32);
#[derive(Component, Default)]
struct Position { x: f32, y: f32 }#[derive(Component)] does most of the work. Behind the scenes the macro generates an impl that registers a ComponentId for the type the first time it's used in a world.
Storage
By default, components are stored in tables (struct-of-arrays per archetype). For components that get added/removed often, opt into sparse-set storage:
#[derive(Component)]
#[component(storage = "SparseSet")]
struct PendingPickup;Tables are fastest for iteration; sparse sets are fastest for add/remove. Use sparse set for marker components that flip frequently. The implementation lives in crates/bevy_ecs/src/storage/.
Required components
A component can declare other components it needs:
#[derive(Component, Default)]
#[require(Transform, Visibility)]
struct MyMarker;When you spawn(MyMarker::default()), Bevy automatically inserts Transform::default() and Visibility::default(). This replaces the older "Bundle" pattern for many cases — instead of remembering to bundle related components together, the component itself declares its dependencies.
Hooks and observers
A component can have lifecycle hooks attached:
impl Component for Health {
fn on_add() -> Option<ComponentHook> {
Some(|mut world, entity, _id| {
// runs when this component is added to an entity
})
}
// …
}Use hooks for synchronous, low-overhead reactions. For more flexible reactions, register an observer:
world.add_observer(|trigger: Trigger<OnAdd, Health>, ...| {
// runs as a deferred event when Health is added
});Hooks run inline; observers run as scheduled commands. Both are useful — hooks for invariant maintenance, observers for higher-level effects.
Required Send + Sync + 'static
Components must be Send + Sync + 'static. The compiler error if they aren't is unmistakable. If you have non-Send data (e.g., an OS handle), wrap it in NonSend-only access patterns or move it to a resource with NonSendMut.
Reflection
To make a component show up in scenes / the BRP / the inspector:
#[derive(Component, Reflect, Default)]
#[reflect(Component, Default)]
struct Health(u32);
app.register_type::<Health>();The reflect_auto_register feature can do the registration step automatically using inventory.
Removing components
world.entity_mut(id).remove::<Health>();
// or via commands
commands.entity(id).remove::<Health>();Removing a component is a structural change — the entity moves to a different archetype. Components removed during a frame appear in RemovedComponents<T> for systems to react.
See also
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.