# How GDExtension Loading and Interface Management Work in Godot Engine

> Understand GDExtension loading and interface management in Godot. Learn how the GDExtensionManager dynamically loads libraries, manages callbacks, and supports hot-reloading for efficient development.

- Repository: [Godot Engine/godot](https://github.com/godotengine/godot)
- Tags: internals
- Published: 2026-02-26

---

**GDExtension loading works through a singleton `GDExtensionManager` that discovers `.gdextension` files, loads shared libraries via `OS::open_dynamic_library`, acquires proc-address getters for interface functions, and initializes extensions across four levels while managing runtime callbacks and editor hot-reloading.**

Godot's GDExtension system is the modern replacement for GDNative, enabling native C/C++ code to integrate with the engine at runtime. The loading process involves a sophisticated pipeline of discovery, dynamic linking, and interface function binding that allows extensions to register classes, methods, and properties without recompiling the engine.

## The GDExtensionManager Singleton

The engine creates a global **`GDExtensionManager`** singleton during early startup to orchestrate all extension operations. This singleton is instantiated in `register_core_types()` within [`core/register_core_types.cpp`](https://github.com/godotengine/godot/blob/main/core/register_core_types.cpp) and added to the engine's global singleton table via `Engine::add_singleton`.

The singleton pattern provides centralized access throughout the engine:

```cpp
static inline GDExtensionManager *singleton = nullptr;
static GDExtensionManager *GDExtensionManager::get_singleton() { return singleton; }

```

All extension operations—loading, initialization, callbacks, and reloading—flow through this manager, ensuring consistent state tracking and lifecycle management.

## Extension Discovery and Loading Pipeline

### Configuration Discovery

The loading process begins with **discovery**. The manager reads [`extension_list.cfg`](https://github.com/godotengine/godot/blob/main/extension_list.cfg) (generated by the editor) to obtain paths to `.gdextension` resource files. Each `.gdextension` file contains metadata specifying the entry symbol and platform-specific library paths:

```gdscript
[configuration]
entry_symbol = "my_extension_init"

[libraries]
windows.debug = "bin/my_extension.windows.debug.dll"
linux.debug   = "bin/my_extension.linux.debug.so"
macos.debug   = "bin/my_extension.macos.debug.dylib"

```

### Library Resolution and Loading

When `GDExtensionManager::load_extension(const String &p_path)` is called, it instantiates a **`GDExtensionLibraryLoader`** to handle the heavy lifting. The loader performs three critical tasks:

1. Parses the `.gdextension` file to resolve the best matching library for the current feature set and platform
2. Locates all dependencies
3. Opens the binary using `OS::open_dynamic_library`

The loading chain proceeds through `load_extension_with_loader`, which instantiates a `GDExtension` resource and calls `extension->open_library(p_path, p_loader)`. Inside `GDExtension::open_library`, the final platform-specific loading occurs:

```cpp
OS::get_singleton()->open_dynamic_library(abs_path, library, &data);

```

Platform implementations (such as [`platform/windows/os_windows.cpp`](https://github.com/godotengine/godot/blob/main/platform/windows/os_windows.cpp) or [`platform/linuxbsd/os_linuxbsd.cpp`](https://github.com/godotengine/godot/blob/main/platform/linuxbsd/os_linuxbsd.cpp)) execute the native `dlopen` or `LoadLibrary` calls and store the returned handle for subsequent symbol resolution.

## Interface Function Acquisition

Once the library is loaded, Godot establishes the **interface function table** that extensions use to call engine APIs. The manager obtains a **proc-address getter** function from the loaded library:

```cpp
GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name);

```

Every engine function exposed to extensions is registered in a static hash map via `register_interface_function`:

```cpp
static void register_interface_function(const StringName &p_name,
                                        GDExtensionInterfaceFunctionPtr p_ptr) {
    gdextension_interface_functions[p_name] = p_ptr;
}

```

The extension's entry point receives the getter and resolves required symbols:

```c
p_interface->classdb_register_class = (GDExtensionInterfaceClassdbRegisterClass)
        p_get_proc_address("classdb_register_class");

```

This design caches function pointers in `gdextension_interface_functions` (defined in [`core/extension/gdextension.h`](https://github.com/godotengine/godot/blob/main/core/extension/gdextension.h)), eliminating the need for repeated OS-level symbol lookups and ensuring high-performance cross-language calls.

## Initialization Levels and Lifecycle

Godot defines four distinct **initialization levels** in `GDExtension::InitializationLevel`:

- **`CORE`** – Initial engine core setup
- **`SERVERS`** – Server singletons available
- **`SCENE`** – Scene types initialized
- **`EDITOR`** – Editor-only classes and tools

During engine startup (`Main::setup()` in [`main/main.cpp`](https://github.com/godotengine/godot/blob/main/main/main.cpp)), the manager iterates through these levels:

```cpp
GDExtensionManager::get_singleton()->initialize_extensions(
        GDExtension::INITIALIZATION_LEVEL_SERVERS);
// ...
GDExtensionManager::get_singleton()->initialize_extensions(
        GDExtension::INITIALIZATION_LEVEL_SCENE);

```

The `initialize_extensions(level)` method checks each loaded extension's `minimum_initialization_level`. If the extension's minimum level is less than or equal to the current level, the manager calls `extension->initialize_library(level)` to trigger the extension's initialization function.

### Runtime Callbacks

Extensions may expose three optional lifecycle callbacks in their `GDExtensionInitialization` struct:

- **`startup`** – Called immediately after library load via `GDExtensionManager::startup`
- **`frame`** – Called every engine frame via `GDExtensionManager::frame`
- **`shutdown`** – Called during engine shutdown via `GDExtensionManager::shutdown`

The manager tracks invocation state to prevent duplicate calls during reload operations.

## Editor Hot-Reloading

When compiled with `TOOLS_ENABLED`, the manager supports **live reloading** of extensions without restarting the editor. The `reload_extension` method implements a careful teardown and restoration sequence:

1. **`prepare_reload()`** – Saves internal state and prepares the extension
2. **`close_library()`** – Unloads the dynamic library handle
3. **Re-open** – Loads the potentially updated binary from the same path
4. **Re-initialize** – Runs initialization up to the current engine level
5. **`finish_reload()`** – Restores instance bindings and completes the transition

This process is implemented in `GDExtensionManager::reload_extension`, utilizing `_unload_extension_internal` for the cleanup phase.

## Implementation Example

A complete extension requires both configuration and implementation code. The `.gdextension` file specifies the entry point, while the C/C++ code implements the initialization:

```c
#include <godot/gdextension_interface.h>

static void GDN_EXPORT my_class_register(GDExtensionInterfaceGetProcAddress p_get_proc_address) {
    GDExtensionClassCreationInfo create_info = {};
    create_info.create_instance_func = my_class_create;
    create_info.free_instance_func   = my_class_free;
    create_info.get_virtual_func    = my_class_get_virtual;
    
    GDExtensionInterfaceClassdbRegisterClass register_class =
        (GDExtensionInterfaceClassdbRegisterClass)p_get_proc_address("classdb_register_class");
    
    register_class("MyClass", "Node", &create_info);
}

extern "C" GDExtensionBool GDN_EXPORT my_extension_init(
        GDExtensionInterfaceGetProcAddress p_get_proc_address,
        GDExtensionClassLibraryPtr p_library,
        GDExtensionInitialization *r_initialization) {
    
    r_initialization->initialize = my_class_register;
    r_initialization->minimum_initialization_level = GDEXTENSION_INITIALIZATION_SCENE;
    return GDExtensionBool(true);
}

```

From GDScript, the registered class behaves like any native engine class:

```gdscript
extends Node

func _ready():
    var obj = MyClass.new()
    print(obj.some_method())

```

## Summary

- **`GDExtensionManager`** is the engine-wide singleton that coordinates all extension operations, created during `register_core_types()`.
- **Discovery** reads [`extension_list.cfg`](https://github.com/godotengine/godot/blob/main/extension_list.cfg) and parses `.gdextension` metadata to locate platform-specific shared libraries.
- **Loading** uses `GDExtensionLibraryLoader` to resolve dependencies and `OS::open_dynamic_library` for platform-specific dynamic linking.
- **Interface functions** are exposed through a proc-address getter pattern, cached in `gdextension_interface_functions` for performance.
- **Initialization levels** (CORE, SERVERS, SCENE, EDITOR) allow extensions to register functionality only when dependent engine systems are ready.
- **Editor hot-reloading** enables iterative development by unloading, updating, and re-initializing extension libraries without restarting Godot.

## Frequently Asked Questions

### How does Godot find which GDExtensions to load?

Godot reads the [`extension_list.cfg`](https://github.com/godotengine/godot/blob/main/extension_list.cfg) file (generated by the editor) which contains paths to `.gdextension` resource files. According to the source code in [`core/extension/gdextension_manager.cpp`](https://github.com/godotengine/godot/blob/main/core/extension/gdextension_manager.cpp), the manager parses these configuration files to determine the entry symbol and select the appropriate platform-specific library binary for the current build profile.

### What is the difference between GDExtension and the old GDNative system?

GDExtension is the successor to GDNative, providing a more stable ABI and cleaner interface management. While GDNative required specific version matching and complex binding logic, GDExtension uses a centralized interface function table (`gdextension_interface_functions`) and standardized initialization levels, making it easier to maintain compatibility across Godot versions.

### Can GDExtensions be reloaded without restarting the editor?

Yes, but only in editor builds (`TOOLS_ENABLED`). The `GDExtensionManager::reload_extension` method handles the entire process: preparing internal state, closing the library handle, reopening the potentially modified binary, and re-initializing to the current level. This is implemented in [`core/extension/gdextension_manager.cpp`](https://github.com/godotengine/godot/blob/main/core/extension/gdextension_manager.cpp) and enables rapid iteration during native extension development.

### What happens if an extension fails to load?

The `load_extension` method returns a `LoadStatus` enum indicating success or specific failure modes (such as file not found or initialization failure). If `open_library` fails in [`core/extension/gdextension.cpp`](https://github.com/godotengine/godot/blob/main/core/extension/gdextension.cpp), the manager cleans up the partially loaded state and returns an error code without crashing the engine, allowing Godot to continue running without the problematic extension.