ECS Design Principles
Design guidance for jecs in Roblox.
Core Mental Model
Think of ECS as a columnar database:
| Database | ECS |
|---|
| Table | Archetype (unique component combination) |
| Column | Component type |
| Row | Entity |
| Query | System iteration |
Design question: "Would I create a separate database column for this?"
Core References
| Topic | Description | Reference |
|---|
| Database Model | ECS as columnar database, normalization, fragmentation | core-database-model |
| Query Design | Multi-entity queries, constraint decomposition, traversal | core-query-design |
Best Practices
Quick Decision Guide
| Question | Answer |
|---|
| Should this be an entity? | Only if it needs per-instance state that changes over time |
| Split or combine? | "Is there a system that needs A but not B?" |
| Tag or data component? | Tags for stable classification (free to add/remove), data for state |
| Relationship or entity ref? | Relationship if reverse lookup needed, entity member otherwise |
| Is fragmentation bad? | Only if thousands of archetypes AND you query broadly |
| When does DOD matter? | Thousands of entities, per-frame, CPU-bound |
Common Mistakes
| Mistake | Why it's bad | Fix |
|---|
| Monolithic components | Cache waste, tight coupling | Split by access pattern |
| Over-atomic components | Query complexity, invalid states | Combine semantic units |
| Frequent add/remove on large entities | Copies all component data | Mutate data component instead |
| Relationships for every link | Fragmentation without benefit | Use entity members for forward-only |
| Cached query inside system | Creates new cache every frame | Create cached queries at module scope |
Key Principles
- Components by access pattern — Group data that systems need together
- Archetype transitions copy data — Adding/removing components copies all
data to new archetype; cheap on small entities, expensive on large ones
- Entity members vs relationships — Use entity members for forward lookup,
relationships for reverse lookup or grouping
- Cache queries at module scope — Never call
.cached() inside a system
- Filter in query — Use with/without, not code conditionals
- Fragmentation can help — Relationships enable efficient grouped queries
<!--
Source references:
- https://github.com/SanderMertens/flecs/blob/master/docs/DesignWithFlecs.md
- https://github.com/SanderMertens/ecs-faq
-->