godot-rust/gdnative
Rust bindings for Godot 3
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4mo ago
- ✓6 active contributors
- ✓Distributed ownership (top contributor 34% of recent commits)
Show all 7 evidence items →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 4mo ago
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/godot-rust/gdnative)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/godot-rust/gdnative on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: godot-rust/gdnative
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/godot-rust/gdnative shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 4mo ago
- 6 active contributors
- Distributed ownership (top contributor 34% of recent commits)
- MIT licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 4mo ago
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live godot-rust/gdnative
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/godot-rust/gdnative.
What it runs against: a local clone of godot-rust/gdnative — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in godot-rust/gdnative | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 158 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of godot-rust/gdnative. If you don't
# have one yet, run these first:
#
# git clone https://github.com/godot-rust/gdnative.git
# cd gdnative
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of godot-rust/gdnative and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "godot-rust/gdnative(\\.git)?\\b" \\
&& ok "origin remote is godot-rust/gdnative" \\
|| miss "origin remote is not godot-rust/gdnative (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "Cargo.toml" \\
&& ok "Cargo.toml" \\
|| miss "missing critical file: Cargo.toml"
test -f "gdnative-sys/src/lib.rs" \\
&& ok "gdnative-sys/src/lib.rs" \\
|| miss "missing critical file: gdnative-sys/src/lib.rs"
test -f "gdnative-core/src/lib.rs" \\
&& ok "gdnative-core/src/lib.rs" \\
|| miss "missing critical file: gdnative-core/src/lib.rs"
test -f "gdnative-derive/src/lib.rs" \\
&& ok "gdnative-derive/src/lib.rs" \\
|| miss "missing critical file: gdnative-derive/src/lib.rs"
test -f "bindings-generator/src/lib.rs" \\
&& ok "bindings-generator/src/lib.rs" \\
|| miss "missing critical file: bindings-generator/src/lib.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 158 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~128d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/godot-rust/gdnative"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
gdnative is a Rust FFI binding layer that lets developers write Godot 3 game engine scripts and plugins in Rust instead of GDScript, with automatic code generation from Godot's C API. It provides memory-safe access to Godot's node system, signals, exports, and async runtime through Rust abstractions, compiled as shared libraries (.so/.dll) that Godot loads at runtime. Monorepo with workspace root (Cargo.toml) managing 18 crates: gdnative (facade), gdnative-core (core types), gdnative-sys (raw FFI), gdnative-derive (proc-macros in impl/proc-macros/), bindings-generator (Godot API parser), gdnative-async (async runtime), plus examples/ (hello-world, spinning-cube, dodge-the-creeps, etc.) and test/. The bindings-generator reads Godot JSON, emits gdnative-bindings crate.
👥Who it's for
Game developers and engine hackers who want to build Godot 3 games or plugins in Rust, leveraging type safety and performance; and contributors who maintain FFI bindings between Rust and C++ (Godot). They need both high-level ergonomic APIs and low-level FFI control.
🌱Maturity & risk
Actively maintained with robust CI (full-ci.yml, minimal-ci.yml, release automation). The codebase shows 1M+ lines of Rust and has well-established patterns (workspace with 18+ member crates). However, it targets Godot 3 specifically, which is in long-term support mode (Godot 4 exists with different bindings). Not abandoned—recent workflows and composable GitHub Actions suggest ongoing development, but adoption may be limited by Godot 3's age.
The bindings-generator (in bindings-generator/src/) is a custom code-generation tool that depends on Godot's JSON API format and must stay in sync—breaking changes to Godot's C ABI could require regeneration. As a single-language binding project for a specific engine version, it's tightly coupled to Godot 3.x; migration to Godot 4 would require a major rewrite. No obvious single-maintainer bottleneck visible, but the FFI surface area is large.
Active areas of work
Release version workflow exists (.github/workflows/release-version.yml) suggesting active versioning. Workflows include Dependabot integration (.github/dependabot.yml) for dependency updates. The examples span basic node scripting to complex game logic (dodge-the-creeps, godot_tps_controller_port). No specific PR/issue data in file list, but CI setup (composite actions for rust, godot, llvm in .github/composite/) indicates ongoing build/test infrastructure work.
🚀Get running
git clone https://github.com/godot-rust/gdnative.git
cd gdnative
cargo build
cargo test
Then explore examples/ (e.g., cd examples/hello-world && cargo build) or read CONTRIBUTING.md and the user guide at https://godot-rust.github.io/gdnative-book.
Daily commands:
No traditional dev server; instead: cargo build --example hello-world produces a .so that Godot loads. For testing: cargo test. For bindings regeneration (rarely needed): run bindings-generator with a Godot API JSON file. See examples/hello-world/Cargo.toml and example.sh for templates.
🗺️Map of the codebase
Cargo.toml— Workspace configuration defining all member crates (gdnative, gdnative-core, gdnative-sys, gdnative-derive, etc.) and their interdependencies.gdnative-sys/src/lib.rs— Low-level FFI bindings to Godot C API; foundation for all higher-level Rust abstractions.gdnative-core/src/lib.rs— Core unsafe wrappers and type definitions over FFI; establishes safety abstractions and object model.gdnative-derive/src/lib.rs— Procedural macro implementation for #[derive(NativeClass)] and #[methods]; critical for the declarative binding pattern.bindings-generator/src/lib.rs— Generates Godot API bindings from JSON schema; maintains consistency between engine updates and Rust bindings.gdnative/src/lib.rs— Main crate re-exporting the public API surface; primary entry point for users.README.md— Overview of the project, its design philosophy, and getting-started guidance for new contributors.
🛠️How to make changes
Add a new NativeClass binding (e.g., a game object)
- Create a new file in your crate (e.g., src/my_actor.rs) with a struct and the #[derive(NativeClass)] attribute (
examples/dodge-the-creeps/src/player.rs) - Implement the #[methods] block to define Godot-callable methods (
examples/dodge-the-creeps/src/player.rs) - Call init_object_instance in your library initialization function (lib.rs) to register the class (
examples/dodge-the-creeps/src/lib.rs) - Create a .gdns file in your Godot project pointing to the compiled library and class name (
examples/dodge-the-creeps/Player.gdns)
Export properties from Rust to Godot Inspector
- Add the #[export] attribute to fields in your NativeClass struct (
examples/builder-export/src/lib.rs) - Use the Builder pattern in your #[methods] impl to set default values via builder methods (
examples/builder-export/src/lib.rs) - Recompile and reload your Godot project to see properties in the Inspector (
examples/builder-export/ExportsArrays.tscn)
Update Godot API bindings to match a new engine version
- Obtain the api.json file from the target Godot version release (
bindings-generator/src/godot_api_json.rs) - Run the bindings-generator crate with the new api.json to regenerate gdnative-bindings (
bindings-generator/src/lib.rs) - Review changes in gdnative-bindings/src/lib.rs and test against examples to ensure compatibility (
examples/dodge-the-creeps/Cargo.toml)
Add async/await support to a callback
- Enable the async feature in your Cargo.toml and use gdnative-async (
Cargo.toml) - In your #[methods] impl, use #[async_ready] or spawn_async for async operations (
gdnative-async/src/lib.rs) - Verify the async runtime is initialized in your library's init function (
examples/dodge-the-creeps/src/lib.rs)
🔧Why these technologies
- Rust — Memory safety without GC; zero-cost abstractions; strong type system enables safe FFI wrapping of Godot C API
- Procedural Macros (proc-macro) — Declarative API for #[derive(NativeClass)] and #[methods] reduces boilerplate and maintains consistency with Godot's reflection model
- FFI (gdnative-sys) — Enables direct binding to Godot's C core without intermediate abstractions; allows zero-cost interop
- Workspace Monorepo (Cargo workspace) — Manages multiple tightly-coupled crates (sys, core, derive, bindings) with shared dependencies; simplifies cross-crate testing and version management
- Code Generation (bindings-generator) — Auto-generates API bindings from Godot JSON schema to ensure consistency across engine versions and reduce manual maintenance
⚖️Trade-offs already made
-
Unsafe FFI layer (gdnative-sys) exposed to crate users via re-export
- Why: Allows advanced users to directly use raw Godot API when safe wrappers are insufficient; unavoidable given Godot's C architecture
- Consequence: Users must carefully manage unsafe blocks and memory lifetime; potential for segfaults if misused
-
Compile-time code generation via macros rather than runtime reflection
- Why: Zero runtime overhead; leverages Rust's type system for compile-time safety checks
- Consequence: More build-time complexity; changes to class definitions require recompilation
-
Single-threaded event loop assumption (no Send/Sync by default)
- Why: Matches Godot's single-threaded main loop model; simplifies callback and state management
- Consequence: Async patterns require explicit opt-in; cross-thread access requires explicit synchronization
-
Auto-generated bindings from JSON schema (gdnative-bindings crate)
- Why: Enables rapid adaptation to Godot engine updates; reduces manual API maintenance burden
- Consequence: Generated code can be verbose; breaking changes in Godot API require regeneration and user migration
🚫Non-goals (don't propose these)
- Runtime hot-reloading of Rust code (requires recompilation and library rebuild)
- Godot 4+ support (this is GDNative for Godot 3.x only; see gdnative 0.11+ for Godot 4 via GDExtension)
- Automatic memory management across language boundaries (requires manual Ref<T> and Instance<T> management)
- Performance optimizations beyond zero-cost abstractions (users responsible for algorithmic efficiency)
- Platform-specific native plugins (only Rust-based plugins; does not wrap C++ addons)
🪤Traps & gotchas
Godot version mismatch: bindings-generator expects a specific Godot JSON API file (path not visible in file list, likely passed at build time); wrong version causes generated bindings to fail. Unsafe FFI boundary: gdnative-sys requires careful lifetime management; Godot can invalidate object references across FFI calls. Proc-macro debugging: errors in gdnative-derive are hard to diagnose (macro-expansion errors); see CONTRIBUTING.md for testing strategies. Feature flags: Some crates may have optional features (e.g., async) that must be enabled in dependent crates' Cargo.toml. C ABI stability: gdnative-sys is regenerated; hand-edits are lost on rebuild.
🏗️Architecture
💡Concepts to learn
- FFI (Foreign Function Interface) — gdnative-sys exposes raw Godot C functions via extern "C"; understanding calling conventions, memory layout, and unsafety is critical for contributors
- Reference Counting (Rc/Arc with interior mutability) — Godot objects are ref-counted; gdnative-core wraps them with Rust Rc<RefCell<>> patterns to provide safe, GC-free memory management
- Procedural Macros (proc-macros) — gdnative-derive uses syn/quote to parse and generate code at compile time; #[derive(NativeClass)] and #[export] are the dev-facing API
- Code Generation from Metadata (JSON → Rust) — bindings-generator parses Godot's JSON API schema and outputs 10k+ lines of Rust; understanding this pipeline is essential for extending binding coverage
- Workspace Monorepo (Cargo workspace) — 18 crates with shared dependencies managed via root Cargo.toml; understanding member crate interdependencies (sys → core → derive) is key to navigation
- Async/await in FFI contexts — gdnative-async bridges Rust futures with Godot's frame-based event loop; non-trivial interop pattern for contributors adding async features
- Object Lifetime & Ownership in GC-less Engines — Godot manages object lifecycles (nodes are parented to scene tree); gdnative must prevent Rust code from holding dangling refs. RefInstance<T> solves this with interior checks.
🔗Related repos
godot-rust/godot-rust— Successor bindings for Godot 4.x using similar architecture; users migrating from Godot 3 would reference thisEmbarkStudios/rust-gpu— GPU shader programming in Rust; orthogonal but often used by Godot developers wanting compute shaders alongside gdnativebevyengine/bevy— Pure-Rust game engine alternative; developers choosing between Godot+gdnative vs. Bevy for Rust game devgodotengine/godot— Official Godot 3 engine repository; gdnative depends on its C ABI and JSON API documentationrust-lang/rust-bindgen— Auto-generates Rust FFI bindings from C headers; inspired/complementary approach to what bindings-generator does hand-rolled
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for bindings-generator output validation
The bindings-generator crate (bindings-generator/src/) generates Rust bindings from Godot's API JSON, but there are no visible integration tests validating that generated bindings compile and match expected signatures. This is critical since breaking changes in generated code would only be caught at user build time. Adding tests that generate bindings for a subset of Godot classes and verify their structure would catch regressions early.
- [ ] Create bindings-generator/tests/integration/ directory
- [ ] Add test that invokes the bindings generator with a test Godot API JSON file
- [ ] Verify generated code compiles and contains expected class/method signatures
- [ ] Add golden file comparisons for generated output (e.g., in bindings-generator/tests/fixtures/)
- [ ] Reference test in bindings-generator/Cargo.toml with [[test]] section
Add GitHub Actions workflow for MSVC/Windows-specific testing
The repo has minimal-ci.yml and full-ci.yml workflows, but they appear Linux-focused. The file structure shows examples like godot_tps_controller_port which may have Windows-specific behavior. Adding a dedicated Windows CI workflow using MSVC toolchain (with llvm composite action already present in .github/composite/llvm/) would catch platform-specific compilation errors and undefined behavior that only manifests on Windows.
- [ ] Create .github/workflows/windows-ci.yml
- [ ] Add matrix strategy for Windows runners (windows-latest) with MSVC toolchain
- [ ] Reuse existing .github/composite/rust and .github/composite/llvm actions
- [ ] Run cargo test and cargo build for core crates (gdnative, gdnative-sys, gdnative-derive)
- [ ] Consider adding an example that exercises Windows-specific Godot features
Document and add tests for the proc-macros (impl/proc-macros) crate
The impl/proc-macros directory is listed in workspace members but has no corresponding documentation or visible tests. Procedural macros (like #[derive(NativeClass)] used throughout examples) are complex and error messages can be cryptic. Adding comprehensive tests with clear error cases and documenting macro behavior would help users debug macro-related issues and prevent regressions.
- [ ] Create impl/proc-macros/tests/ directory with integration tests
- [ ] Add test cases for each derive macro (e.g., NativeClass, ToVariant, FromVariant) with valid and invalid inputs
- [ ] Use trybuild crate to test macro error messages (add to Cargo.toml)
- [ ] Create impl/proc-macros/MACRO_GUIDE.md documenting what each macro does and supported attributes
- [ ] Reference macro documentation in main README.md under a 'Procedural Macros' section
🌿Good first issues
- Add documentation examples to gdnative-async/src/: the async runtime crate has minimal inline examples, but examples/signals exists; porting that to doc comments would help new users. See gdnative-async/src/lib.rs.
- Expand bindings-generator/src/special_methods.rs: Godot has operator overloads (e.g., Vector3 + Vector3) not yet code-generated. Add a new variant to the generator to emit operator trait impls and test with examples/builder-export.
- Add missing tests for gdnative-core/src/ type conversions (e.g., Variant → i32): currently no tests visible in file list for the core type marshaling logic; write unit tests in gdnative-core/tests/ and add to CI.
⭐Top contributors
Click to expand
Top contributors
- @chitoyuu — 34 commits
- @bors[bot] — 27 commits
- @Bromeon — 20 commits
- @dependabot[bot] — 17 commits
- @hero-clashes — 1 commits
📝Recent commits
Click to expand
Recent commits
2cc150a— End of an era (Bromeon)ea72d59— Note about maintenance (Bromeon)639aae7— Merge pull request #1072 from godot-rust/dependabot/cargo/glam-0.27 (Bromeon)8072539— Merge pull request #1070 from godot-rust/dependabot/cargo/heck-0.5 (Bromeon)5f380a7— Merge pull request #1065 from godot-rust/dependabot/cargo/proc-macro-crate-3 (chitoyuu)43afc1a— Update proc-macro-crate requirement from 2 to 3 (dependabot[bot])8e5fdaf— Update heck requirement from 0.4 to 0.5 (dependabot[bot])c1de94d— Update glam requirement from 0.25 to 0.27 (dependabot[bot])0763d73— Merge pull request #1074 from godot-rust/qol/tools (Bromeon)8516ff0— Change syn minimal version to 1.0.84 (Bromeon)
🔒Security observations
The gdnative repository demonstrates generally good security practices as a Rust bindings library, with proper use of Cargo workspaces and automated CI/CD. However, there is a critical issue with exposed token files in version control that requires immediate remediation. Additional concerns include the absence of security policy documentation, reliance on unsafe FFI code that requires careful auditing, and git submodule dependencies that need verification. The project should implement responsible disclosure guidelines and enhance supply chain security practices. Overall security posture is moderate with room for improvement in documentation and credential management.
- Medium · Exposed GitHub Token in Repository —
.github/external-config/public-docs-token.txt. The file '.github/external-config/public-docs-token.txt' suggests storage of authentication tokens in the repository. Even if this is a public token, storing credentials in version control is a security anti-pattern and could lead to token compromise if the file contains sensitive data. Fix: Remove the token file from the repository immediately. Use GitHub Secrets for sensitive credentials instead. If the token was committed, rotate it. Add 'public-docs-token.txt' to .gitignore to prevent future commits. - Low · Missing Security Policy Documentation —
Repository root. There is no SECURITY.md file visible in the repository root. This file typically documents how users should report security vulnerabilities responsibly. The absence of this guidance may lead to public vulnerability disclosures instead of responsible disclosure. Fix: Create a SECURITY.md file documenting responsible disclosure procedures, security contact information, and vulnerability response timelines. Reference: https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository - Low · Workspace Dependency Management —
Cargo.toml. The Cargo.toml workspace includes 'miniserde' with opt-level = 0 in dev profile. While not a direct vulnerability, the workspace manages multiple interdependent crates (gdnative-sys, gdnative-core, gdnative-bindings, etc.) that perform FFI with Godot. FFI code requires careful auditing for memory safety issues. Fix: Ensure all FFI-related crates (particularly gdnative-sys) undergo regular security audits. Use 'cargo audit' to check for known vulnerabilities in dependencies. Consider using tools like 'miri' for undefined behavior detection in unsafe code. - Low · Submodule Dependency —
.gitmodules. The .gitmodules file indicates this repository uses git submodules. Submodules can introduce supply chain risks if not properly verified, and they may contain outdated or compromised code. Fix: Verify the integrity of all submodules regularly. Document which submodules are used and why. Consider using git submodule update --init --recursive with caution and verify commit hashes of submodule references. - Low · Multiple Build Workflows Without Visibility Controls —
.github/workflows/. The repository contains multiple GitHub Actions workflows (full-ci.yml, minimal-ci.yml, release-version.yml, update-docs.yml) without visible environment protection or approval requirements. This could allow unauthorized modifications through CI/CD if branch protection is misconfigured. Fix: Implement branch protection rules requiring reviews for pull requests affecting protected branches. Use GitHub environment protection rules for sensitive workflows like 'release-version.yml'. Audit workflow permissions (GITHUB_TOKEN scope) to ensure least privilege access.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.