What Does entity.spawn Do in Bevy
In Bevy, entity.spawn creates a new entity and assigns it a unique identifier within the world. It accepts components that define its data and behavior, returning an Entity handle for later reference. Spawning is the primary mechanism for introducing dynamic objects into your game or app, whether at startup or during runtime. This guide explains how to use spawn effectively, the differences between spawning commands and direct world calls, and how to structure your code for long-lived, maintainable projects.
Direct Spawning vs Commands: Why the Distinction Matters
Bevy separates immediate world modification from schedule-safe mutation through commands. Directly calling world.spawn is low-level and appropriate during setup or within systems that already hold World access. In contrast, commands.spawn queues work to be applied at the end of the current system stage, preventing borrow conflicts. Understanding when to use each approach is essential for writing safe, deadlock-free systems that scale as your app grows.
When to Use World::spawn Directly
- During app startup in
Startupsystems where you own the world - Inside non-scheduled setup code or plugins that run before stages begin
- When constructing small, contained worlds or tests without complex scheduling
When to Use Commands::spawn
- In user systems running inside the main schedule
- When systems that read and write entities must remain borrow-safe
- To avoid runtime panics caused by simultaneous access to the entity registry
Components and Bundles with Spawn
You can attach any component or bundle to a spawned entity by passing them as arguments to spawn. Components store per-entity data, while bundles group multiple components together for reuse. Using bundles keeps your code DRY and expressive, especially for complex objects like players or enemies. You can also spawn with no components, then add them later through separate commands or systems.
Example: Spawning a Player Bundle
commands.spawn((Player, Transform::default(), Velocity::default()));
Entity Lifetimes and Despawning
Entities persist until explicitly despawned or until their parent entity is despawned in a hierarchy. Despawning removes an entity and all its children, freeing resources and preventing leaks. Always prefer commands to despawn rather than manually removing components. This ensures consistency across stages and prevents use-after-free bugs when systems access the entity immediately after despawning.
Practical Patterns and Safety Guidelines
Common patterns include spawning during Startup, storing entity handles in res or assets, and despawning in response to game events. To maintain safety, avoid storing raw entity references across stages unless you manage dependencies carefully. Use Commands for runtime spawns, and keep system code focused on processing rather than world mutation. For large projects, encapsulate spawning logic in dedicated builder functions or plugins to improve readability and testability.
Comparison: Command Spawn vs World Spawn
| Aspect | Commands::spawn | World::spawn |
|---|---|---|
| When safe to use | Inside schedule stages | Outside stages or during setup |
| Borrow safety | Stage-managed, reduces conflicts | Manual; prone to conflicts if misused |
| Use case example | Gameplay runtime spawning | App build-time entity creation |
| Performance impact | Minimal overhead, batched at end of stage | Immediate, no staging overhead |