How Hot Reloading Works in gdext-nim: Configuration and Limitations
Hot reloading in gdext-nim is enabled by setting reloadable = true in the .gdextension configuration, allowing Godot’s GDExtensionManager to unload and reload the shared library when the editor regains focus after a rebuild.
gdext-nim is a Nim binding for Godot 4’s GDExtension API that supports hot reloading of native shared libraries during development. By marking an extension as reloadable in the configuration DSL, developers can iterate on Nim code without restarting the Godot editor. This article examines the implementation in the source code, the exact reload mechanism, and the critical limitations you must account for in production workflows.
Enabling Hot Reloading in gdext-nim
The reload capability is controlled through the .gdextension file generated during the build process. According to the godot-nim/gdext-nim source code, two specific files handle this configuration: the DSL definition and the build configuration helper.
The Configuration DSL
In src/gdext/private/configdsl.nim, the configuration DSL exposes the reloadable entry that writes the flag to the final INI file:
config.eval:
entry_symbol = "init_library"
compatibility_minimum = 4.6
reloadable = true # <─ enables hot-reload
The Build Configuration Step
During the configure build step defined in src/gdext/buildconf.nim, the system automatically injects the reloadable flag into the configuration:
configuration.update(setting.updateMethod, "reloadable", "true")
This generates a .gdextension file containing:
[configuration]
entry_symbol = "init_library"
compatibility_minimum = 4.6
reloadable = true
When this file is present, Godot’s GDExtensionManager recognizes the library as eligible for hot reloading.
The Hot Reloading Workflow
Once enabled, the reload process is triggered by Godot’s editor lifecycle rather than explicit Nim code.
How Godot Triggers the Reload
Godot exposes the reload capability through GDExtensionManager.reload_extension(path), which gdext-nim binds in src/gdext/classes/gdgdextensionmanager.nim:
# From gdgdextensionmanager.nim
proc reloadExtension*(extension: String): Error {.gdcall.}
When the editor window regains focus after a successful build, Godot automatically executes this method for any extension marked reloadable = true. As noted in the tutorial and development guide, you simply rebuild and focus the editor to trigger the update.
What Happens During a Reload
The engine performs four distinct operations:
- Unload the previously loaded shared library using the internal
unload_extensionbinding. - Load the new library binary via
load_extension. - Re-register all classes, methods, signals, and properties defined in Nim through the
init_libraryentry point. - Preserve existing node instances while re-initializing their fields through the newly registered constructors.
Limitations of gdext Hot Reloading
While hot reloading accelerates development, the implementation has specific constraints regarding state management and structural changes.
Structural Fragility
Adding new classes or methods works reliably, but removing classes, changing inheritance hierarchies, or altering exported property layouts can leave the editor in an inconsistent state. The documentation advises a full editor restart if puzzling errors appear after such changes.
Persistent Runtime State
Because the Nim runtime does not reset process memory during a reload, module-level globals and static data persist across reloads. You must manually re-initialize cached state in methods like _ready to avoid undefined behavior.
Platform and Workflow Constraints
- Editor focus requirement: Godot checks for changes only when the editor window gains focus. If you remain in an external IDE, the reload waits until you switch back.
- Windows file locks: On Windows, the build script works around DLL locks by writing to a temporary file and renaming it, but occasional lock contention may still require a manual restart.
- Shared library only: Hot reloading requires dynamic library builds (
.so,.dll,.dylib). Static builds cannot be hot-reloaded.
Error Handling Limitations
If the new library fails to load (e.g., missing symbols), Godot logs an error but continues using the previously loaded version. This silent failure may hide problems until you manually restart the editor.
Practical Implementation Examples
The following patterns demonstrate safe hot reloading practices based on the source code structure.
Basic Configuration
A minimal bootstrap.nim entry point that generates a reloadable extension:
import gdext
import classes/gdMyClass # Your {.gdsync.} classes
GDExtensionEntryPoint # Generates the .gdextension file with reloadable = true
Build and reload:
gdextwiz build # Compiles to libnim.so
# Focus Godot editor to trigger automatic reload
Handling Persistent State
Reset module-level state after reloads by implementing initialization logic in _ready:
type MyClass* {.gdsync.} = ptr object of Node
counter*: int = 0
method _ready(self: MyClass) {.gdsync.} =
# Re-initialize after hot reload
self.counter = 0
print "State reset after reload"
Forcing a Manual Reload
From GDScript, you can trigger a reload programmatically:
var manager = Engine.get_singleton("GDExtensionManager")
manager.reload_extension("res://my_extension.gdextension")
Summary
- Enable hot reloading by setting
reloadable = truein the configuration DSL (src/gdext/private/configdsl.nim), whichsrc/gdext/buildconf.niminjects during the configure step. - Godot’s
GDExtensionManager.reload_extensionunloads and reloads the shared library when the editor regains focus after a build. - New classes and methods register automatically, but structural changes (removed classes, property layout changes) often require a full editor restart.
- Global variables and cached resources survive reloads; explicitly reset state in
_readymethods. - The feature works only with dynamic shared libraries and requires the editor window to receive focus to detect changes.
Frequently Asked Questions
How do I enable hot reloading in a gdext-nim project?
Set reloadable = true inside the config.eval block in your Nim source or rely on the default GDExtensionEntryPoint template, which generates a .gdextension file containing reloadable = true. Rebuild with gdextwiz build and focus the Godot editor to trigger the reload.
Why does my gdext extension not reload after building?
Godot checks for file changes only when the editor window gains focus. If you stay in your IDE or terminal, the reload will not trigger until you switch back to the editor. Additionally, ensure your .gdextension file contains the reloadable = true flag and that you are building a dynamic shared library (not a static binary).
Can I hot reload changes to class properties or inheritance in gdext-nim?
Adding properties or methods generally works, but removing classes, changing inheritance hierarchies, or altering the memory layout of exported properties can corrupt the editor state. If you encounter cryptic errors after such changes, save your work and restart the Godot editor completely.
How do I handle global variables that persist across hot reloads?
Module-level globals in Nim survive hot reloads because the process memory is not reset. You must manually re-initialize any cached data or singletons in your class's _ready method or another initialization hook to ensure they match the newly loaded library's state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →