Open-Source Wikis

/

Bevy

/

Primitives

/

Component

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

  • Bundle — group of components.
  • Entity — what components are attached to.
  • Observer — reactive handlers for component lifecycle.
  • bevy_ecs — implementation.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Component – Bevy wiki | Factory