Library / SDK
csprance/gecs avatar
csprance/gecs

GECS adds an entity component system to Godot 4.6 and keeps nodes in the loop

Godot Entity Component System - GECS

619 stars45 forksGDScriptCC0-1.0

At a glance

What is it?
GECS is a Godot addon that layers entities, components, systems and relationships over the engine's node tree, with a query builder, a debug viewer and a step debugger. It requires Godot 4.6 or newer, and the licence identifiers in the project disagree with each other.
Who is it for?
Adopt GECS when your Godot project has grown enough that scene hierarchy has become the wrong place to keep game logic, and you want query filtered systems with a step debugger to see why an entity moved. Do not adopt it on Godot 4.5 or earlier, since the documentation says versions up to 4.5 cannot parse the per-system performance monitor code.
Can I use it commercially?
Yes. CC0-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 34 days ago.
What is it written in?
Mainly GDScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Entities beside nodes, not instead of them

GECS is an entity component system for Godot, and the interesting part of its pitch is that it does not ask you to abandon the node system. The stated goal is clean separation of data and logic while still working with nodes, scenes and the editor. In practice that means you get two ways of organising things at once, and the design decisions follow from that. An entity is a plain object created with `Entity.new()`, components are data classes that extend `Component`, and systems are logic classes that extend `System` and declare which components they care about. The engine keeps running its usual node tree, but the parts of your game that fit the pattern can move into query filtered systems. For a Godot team that likes the editor but finds inheritance-heavy scene trees awkward for simulation logic, that hybrid is the whole appeal.

Systems declare a query and receive the matching entities

The data flow is straightforward once you accept the vocabulary. A system overrides `query()` to return a `QueryBuilder`, built from `q.with_all([...])`, and it overrides `process()` to receive the matching entities, the components and the delta. The registration path is `ECS.world.add_system(...)` followed by `ECS.process(delta)` from your `_process` call, so the framework does not take over the game loop, it runs inside it. Queries can find entities by component, by relationship or by property, and the documentation mentions automatic caching behind the optimised queries, so the same query issued every frame should not rebuild its match set from scratch. Because a system only sees entities matching its query, the usual ECS benefit applies: adding a component changes which entities a system touches without editing the system. The cost is that a reader now has to follow the query to know what code affects an object.

The export-time default value trap in component properties

There is one rule in the quick start that deserves more attention than it gets, and it is stated at the top of the sample code: all component properties need a default value or Godot will error on export. The documented patterns are two. Either declare an exported variable with a default and no constructor, or give the class an `_init()` with a parameter while also giving the property a default. The sample code shows the first form with `max_health` and `current_health` on `C_Health`, and the second with `direction` on `C_Velocity`, where `_init(v: Vector3 = Vector3.ZERO)` assigns into an exported variable that already defaults to `Vector3.ZERO`. This is a Godot export constraint meeting an ECS convention, and it means component classes cannot be written the way you would write an ordinary resource with required fields. Plan for it early, because every component you add later has to follow the same shape.

Relationships and observers for cases queries cannot express

Two features extend the model past simple component matching. The first is relationships, created with `Relationship.new(C_AllyTo.new(), target)` and attached with `add_relationship`, which links one entity to another with a typed tag rather than by storing a reference in a component. The in-repo inventory example is described as relationship based, with item templates and a deferred action queue, which suggests the relationship layer is where item and target references belong. The second is observers, documented as reactive systems for component changes, so a system can react when a component appears or changes rather than polling for it each frame. Both of these are the standard escape hatches from a rigid ECS, and both are where most real projects will spend their design effort. The query builder itself also supports property based filtering, which the advanced documentation covers separately, and that is the feature to reach for when a component match is too coarse.

A step debugger and a debug viewer for the hard part of ECS work

The tooling is what separates this addon from a textbook ECS implementation. The debug viewer gives real-time inspection and performance monitoring, and the step debugger, added in v9.3.0, pauses the ECS and steps it forward one system, one archetype or one entity at a time, keeping a per-step mutation log, supporting breakpoints and drawing an entity relationship graph. The v9.3.3 release added explorer polling and breakpoint controls, and v9.3.4 added network spawn signals, which is the point at which the separate GECS Network Module starts to matter. None of this is decoration. The hardest part of running an ECS is explaining why one entity was processed and another was not, and a mutation log plus a relationship graph is a direct answer to that. The repository even carries a handover document named HANDOFF_DEBUGGER_PERF.md, which suggests the debugger has been the focus of recent work rather than an afterthought.

Installing into a project and pointing it at a Godot 4.6 editor

Installation is an addon, and the documentation gives three routes. The submodule route points at a release branch:

bash
git submodule add -b release-v8.0.0 https://github.com/csprance/gecs.git addons/gecs

The manual route is to download the release zip, copy `addons/gecs/` into the project and enable the plugin in Project Settings > Plugins. The third is to search for GECS in the editor's AssetLib tab, install, then enable the plugin in the same place. Every route ends with the plugin enabled. The version constraint is strict: Godot 4.6 or newer, because versions up to and including 4.5 cannot parse the per-system performance monitor code introduced in GECS v8.0.0. The documentation then points at a getting started guide, a core concepts guide covering entities, components, systems and relationships, and a set of example projects including an inventory example, a card game, a multimesh example, a network example, a sheep herding example and a stress test, plus separate GECS-101, a zombies action game and a breakout clone.

Licence confusion and the cost of a major version jump

The licence needs a moment of your attention, because the identifiers do not agree. The project record carries CC0-1.0 as the licence identifier, while the README states MIT and points to a LICENSE file for details. Those are very different instruments: MIT is a permissive licence with an attribution requirement, and CC0 is a public domain dedication. Whichever is correct, you have to read the LICENSE file before shipping. The other upgrade cost is version shaped. The submodule example still points at `release-v8.0.0`, while the published releases listed are v9.3.4 on 2026-09-19, v9.3.3 on 2026-09-12 and v9.3.0 on 2026-09-11, so the branch name in the install snippet trails the current release line by a major version. The last push to the repository was on 2026-09-19. The release names also read as a roadmap of the tooling: v9.3.0 added the explorer and step debugger, v9.3.3 added polling and breakpoint controls, and v9.3.4 added network spawn signals.

Editorial conclusion

Adopt GECS when your Godot project has grown enough that scene hierarchy has become the wrong place to keep game logic, and you want query filtered systems with a step debugger to see why an entity moved. Do not adopt it on Godot 4.5 or earlier, since the documentation says versions up to 4.5 cannot parse the per-system performance monitor code. Before you start, settle the licence question by reading the LICENSE file, because the project identifier and the README name different licences, and confirm that the export-time default value rule for component properties fits your component design.

Frequently asked questions

What Godot version does GECS require?

Godot 4.6 or newer. The documentation notes that versions up to and including 4.5 cannot parse the per-system performance monitor code introduced in GECS v8.0.0.

How do I install GECS in a Godot project?

Add it as a git submodule into `addons/gecs`, or copy `addons/gecs/` from the release zip into the project, or install it from the editor's AssetLib tab. In every case you then enable the plugin in Project Settings > Plugins.

Why do my component properties need default values in GECS?

All component properties need a default value or Godot errors on export. The documented patterns are an exported variable with a default and no constructor, or an `_init()` with a parameter alongside a default on the property.

What licence is GECS released under?

The README states MIT and points to the LICENSE file for details, while the project record carries CC0-1.0 as the licence identifier. Read the LICENSE file before shipping, since the two identifiers do not match.

Official sources

  1. csprance/gecs on GitHub
  2. Issues
  3. License: CC0-1.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/csprance-gecs.svg)](https://hysenlabs.com/projects/csprance-gecs)

Was this useful?