Library / SDK
godot-rust/gdext avatar
godot-rust/gdext

gdext: Rust bindings for Godot 4, and what they cost you

Rust bindings for Godot 4

5,235 stars315 forksRustMPL-2.0

At a glance

What is it?
gdext maps most of Godot 4's API into type-safe Rust through the GDExtension interface. It suits teams with Rust experience who want static typing inside an existing Godot project, not people looking for a lighter scripting language.
Who is it for?
Adopt gdext if you already write Rust and want a typed slice of your Godot 4 project, accepting that the crates.io release trails master and that Wasm, Android and iOS support is described as experimental with thin documentation. Do not adopt it as a first language for a small 2D game, where GDScript removes the build step entirely.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

What gdext adds to a Godot 4 project

Godot ships GDScript as its own language, and its GDExtension API exists so third-party languages and libraries can plug into the engine. gdext is the Rust side of that arrangement. The README frames the binding as an alternative to GDScript with a focus on type safety, scalability and performance, and states that the two languages can be mixed in one project, with custom Rust APIs callable type-safely from GDScript.

That mixing is the point. You are not choosing Rust instead of Godot. You keep scenes, resources and the editor, and move the parts where dynamic typing gets expensive into Rust. A damage calculation, an inventory model, a pathfinding loop: anything where a typo in a property name would otherwise surface at runtime. The audience is narrower than the engine's own: developers who already know Rust, or who are willing to learn it, and who have a project large enough that the compile step pays for itself.

How the binding actually works

The workspace layout shows the mechanism. godot-bindings, godot-codegen and godot-ffi sit underneath godot-core, godot-macros, godot-cell and the user-facing godot crate. The codegen crate consumes gdextension-api, which the workspace pins to version 0.5.0 from the godot-rust/godot4-prebuilt repository on the release-v0.5 branch. That is the JSON description of Godot's own API, and the build generates Rust bindings from it. This is why the project can claim that the vast majority of Godot APIs have been mapped to Rust: the mapping is generated, not hand-written.

The macro layer is what makes the generated code usable. In the README's example, #[derive(GodotClass)] declares a class, #[class(init, base=Sprite2D)] sets automatic initialization and inheritance, and #[godot_api] marks impl blocks that expose virtual methods or #[func] methods to GDScript. Fields carry attributes too: #[init(val = 100)] initializes a plain field, and #[init(node = "Ui/HealthBar")] resolves a scene-tree path into an OnReady<Gd<ProgressBar>> that is populated when _ready runs. Signals are typed, so value_changed().connect(|hp| ...) takes a closure whose parameter type comes from the signal definition.

The trade-off is visible in the same example. Inheritance is expressed through composition: the struct holds a base: Base<Sprite2D> field, and calls that need the engine object go through self.base_mut(). The README is candid that interacting with Godot as a C++ engine sometimes forces unconventional approaches. Rust developers coming from pure crates will find the base field and the macro attributes unfamiliar.

Getting started with gdext: the book, the toolchain and a first class

The README does not print a cargo add line or any install command. It points to the godot-rust book as the best place to start, to the API docs, and to the demo-projects repository for runnable examples. The workspace manifest states the toolchain floor as edition 2024 and rust-version 1.94, and the README's motivating example is the code the project itself puts forward as a first look at the API.

That example declares a Player class inheriting Sprite2D, with attribute-initialized fields, an OnReady child node and a typed signal connection:

rust
use godot::classes::{ISprite2D, ProgressBar, Sprite2D};
use godot::prelude::*;

// Declare the Player class inheriting Sprite2D.
#[derive(GodotClass)]
#[class(init, base=Sprite2D)] // Automatic initialization, no manual init() needed.
struct Player {
    // Inheritance via composition: access to Sprite2D methods.
    base: Base<Sprite2D>,

    // #[class(init)] above allows attribute-initialization of fields.
    #[init(val = 100)]
    hitpoints: i32,

    // Access to a child node, auto-initialized when _ready() is called.
    #[init(node = "Ui/HealthBar")] // <- Path to the node in the scene tree.
    health_bar: OnReady<Gd<ProgressBar>>,
}

The same example continues with the virtual method and the custom method exposed to GDScript:

rust
// Implement Godot's virtual methods via predefined trait.
#[godot_api]
impl ISprite2D for Player {
    // Override the `_ready` method.
    fn ready(&mut self) {
        godot_print!("Player ready!");

        // Health bar is already initialized and straightforward to access.
        self.health_bar.set_max(self.hitpoints as f64);
        self.health_bar.set_value(self.hitpoints as f64);

        // Connect type-safe signal: print whenever the health bar is updated.
        self.health_bar.signals().value_changed().connect(|hp| {
            godot_print!("Health changed to: {hp}");
        });
    }
}

And the part GDScript can call:

rust
// Implement custom methods that can be called from GDScript.
#[godot_api]
impl Player {
    #[func]
    fn take_damage(&mut self, damage: i32) {
        self.hitpoints -= damage;
        godot_print!("Player hit! HP left: {}", self.hitpoints);

        // Update health bar.
        self.health_bar.set_value(self.hitpoints as f64);

        // Call Node methods on self, via mutable base access.
        if self.hitpoints <= 0 {
            self.base_mut().queue_free();
        }
    }
}

What you should see when this runs is the godot_print output on _ready and on each health change; the README does not show the engine-side .gdextension configuration, and the book is where the project says that setup lives.

Where gdext is the wrong tool

The README states plainly that breaking changes are occasionally introduced, motivated by improved user experience or upstream changes, and that crates.io releases adhere to SemVer but lag behind the master branch. If your project needs a fix that landed on master, you are either waiting for the next release or tracking a branch. The last push to the repository was on 2026-09-22, and the most recent release listed is v0.5.5 from 2026-08-09, so the gap between the two is real and not hypothetical.

Platform support is the second boundary. The README describes Wasm, Android and iOS support as experimental, with documentation and tooling still lacking. For a desktop game that is irrelevant. For a mobile or web target it changes the risk calculation, and the README does not claim otherwise.

The third case is scale. A small 2D game, a prototype, a jam entry: GDScript has no compile step and no FFI boundary, and adding a Rust crate plus a .gdextension file plus a build pipeline is more moving parts than the project needs. gdext is for codebases where the typing pays for the build.

gdext against GDExtension in C++

The direct alternative is writing the extension in C++ against the same GDExtension API. Both approaches produce a native library that Godot loads, and both are generated from the engine's API description, so the surface area is comparable. The difference is in what the compiler enforces and what you maintain.

In C++ you manage the engine object lifetime yourself and the API is the engine's own C++ shape, which means no translation layer to learn. In gdext the generated bindings and the macro layer sit between you and that shape, and in exchange you get ownership and borrow rules checked at compile time, plus the typed signal connections and macro-declared classes shown above. The README's own framing is that APIs are designed to be safe and idiomatic Rust wherever possible. Whether that is worth the indirection depends on how much of your team already writes Rust. A team fluent in C++ gains little from the extra layer; a team already shipping Rust services gains consistency across the stack.

Maintenance, upgrades and the MPL-2.0 terms

The repository is not archived and its last push was on 2026-09-22, with three releases in the four months before that. The README describes an elaborate CI suite covering clippy, unit tests, engine integration tests and memory sanitizers, and notes that hot-reload is tested as well. The workspace confirms the integration test setup: itest/rust, itest/repo-tweak, itest/hot-reload/rust and itest/itest-dependency are workspace members, and a dedicated itest-bench profile with fat LTO and a single codegen unit exists specifically so benchmarks are not skewed by codegen differences.

Upgrade cost centres on the gdextension-api pin and the breaking-change policy. Because the bindings are generated from a specific API description on a release branch, moving to a new Godot version means moving that pin, and the project's stated practice is to accompany breaking changes with migration guides. Budget for reading them at each minor bump rather than assuming a drop-in upgrade.

On licensing, the project uses Mozilla Public License 2.0. The README explains the intent: you can use the library commercially and keep your own code closed-source, and the condition is that changes to gdext itself must be made available, and only those changes. That is the project's own description of the terms, not legal advice; if you plan to modify the library and ship it, have counsel read the licence text in License.txt.

Editorial conclusion

Adopt gdext if you already write Rust and want a typed slice of your Godot 4 project, accepting that the crates.io release trails master and that Wasm, Android and iOS support is described as experimental with thin documentation. Do not adopt it as a first language for a small 2D game, where GDScript removes the build step entirely. Before committing, verify that the Godot version you ship matches the gdextension-api version pinned in the release branch you select, and read the API stability page in the book, since breaking changes do arrive with migration guides.

Frequently asked questions

What is gdext in Godot?

It is a library that integrates the Rust language with Godot 4 through the engine's GDExtension API. The README describes it as an alternative to GDScript with a focus on type safety, scalability and performance, and says the two languages can be mixed in one project.

Which Rust version and edition does gdext require?

The workspace manifest sets edition 2024 and rust-version 1.94, so that is the floor the repository declares for building it.

Can I call Rust code from GDScript with gdext?

Yes. The README says custom Rust APIs can be called type-safely from GDScript, and methods marked with the #[func] attribute inside a #[godot_api] impl block are exposed that way.

What licence does gdext use?

Mozilla Public License 2.0. The README states you can use the library commercially and keep your own code closed-source, with the condition that changes to godot-rust itself must be made available.

Why do gdext crates.io releases lag behind master?

The README says releases adhere to SemVer but lag a bit behind the master branch, and that breaking changes are occasionally introduced with migration guides.

Official sources

  1. godot-rust/gdext on GitHub
  2. License: MPL-2.0
  3. Project website
  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/godot-rust-gdext.svg)](https://hysenlabs.com/projects/godot-rust-gdext)