Quick answer: The class is not being registered during the initialization phase. Ensure your register_types.

Here is how to fix Godot GDExtension class not registered. You write a C++ class using godot-cpp, compile it as a GDExtension, and place the shared library in your project. But the class does not appear in the editor's "Create New Node" dialog, scripts cannot find it, and there are no error messages in the console. This is almost always caused by a missing or incorrect registration call in register_types.cpp, a misconfigured .gdextension file, or a version mismatch between godot-cpp and your Godot editor.

How GDExtension Class Registration Works

When Godot loads a GDExtension, it calls an entry point function defined in your shared library. This function sets up initialization callbacks for different levels: core, servers, scene, and editor. Your custom node classes must be registered at the MODULE_INITIALIZATION_LEVEL_SCENE level. If the registration call is missing, in the wrong initialization level, or the entry point is not properly configured, Godot loads the library silently but never learns about your classes.

The registration flow is: Godot reads the .gdextension file, loads the shared library, calls the entry point, receives initialization callbacks, then calls each callback at the appropriate time during engine startup. Any break in this chain means your class is invisible.

Fix register_types.cpp

The most common cause is a missing or incorrect register_types.cpp file. This file must define the initialization and termination functions and register every class you want Godot to know about.

// register_types.cpp - correct setup
#include "register_types.h"
#include "my_custom_node.h"

#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/core/class_db.hpp>

using namespace godot;

void initialize_my_extension(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    // Register every custom class here
    ClassDB::register_class<MyCustomNode>();
}

void uninitialize_my_extension(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
}

extern "C" {
GDExtensionBool GDE_EXPORT my_extension_init(
    GDExtensionInterfaceGetProcAddress p_get_proc_address,
    const GDExtensionClassLibraryPtr p_library,
    GDExtensionInitialization *r_initialization
) {
    godot::GDExtensionBinding::InitObject init_obj(
        p_get_proc_address, p_library, r_initialization
    );

    init_obj.register_initializer(initialize_my_extension);
    init_obj.register_terminator(uninitialize_my_extension);
    init_obj.set_minimum_library_initialization_level(
        MODULE_INITIALIZATION_LEVEL_SCENE
    );

    return init_obj.init();
}
}

The critical points: the entry point function name must match what is specified in your .gdextension file, the initialization level must be MODULE_INITIALIZATION_LEVEL_SCENE for node classes, and every class you want to use must have its own register_class call.

GDCLASS Macro in Your Header

Every class registered with GDExtension must include the GDCLASS macro in the class body. Without it, the binding system cannot generate the necessary metadata.

// my_custom_node.h - correct class declaration
#ifndef MY_CUSTOM_NODE_H
#define MY_CUSTOM_NODE_H

#include <godot_cpp/classes/node3d.hpp>

namespace godot {

class MyCustomNode : public Node3D {
    GDCLASS(MyCustomNode, Node3D)  // Required! First arg = this class, second = parent

private:
    float speed = 10.0f;

protected:
    static void _bind_methods();  // Must be declared and defined

public:
    MyCustomNode();
    ~MyCustomNode();

    void set_speed(float p_speed);
    float get_speed() const;

    void _process(double delta) override;
};

}

#endif

The _bind_methods function must also be defined, even if empty. This is where you expose properties, methods, and signals to GDScript and the editor. A missing _bind_methods definition causes a linker error or silent registration failure.

// my_custom_node.cpp - bind methods
#include "my_custom_node.h"
#include <godot_cpp/core/class_db.hpp>

using namespace godot;

void MyCustomNode::_bind_methods() {
    ClassDB::bind_method(D_METHOD("get_speed"), &MyCustomNode::get_speed);
    ClassDB::bind_method(D_METHOD("set_speed", "speed"), &MyCustomNode::set_speed);
    ADD_PROPERTY(
        PropertyInfo(Variant::FLOAT, "speed"),
        "set_speed", "get_speed"
    );
}

The .gdextension File

The .gdextension file tells Godot where to find your shared library and how to load it. A misconfigured file is the second most common cause of classes not appearing.

; my_extension.gdextension - correct configuration
[configuration]
entry_symbol = "my_extension_init"
compatibility_minimum = "4.2"
reloadable = true

[libraries]
linux.debug.x86_64 = "res://bin/libmyextension.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libmyextension.linux.template_release.x86_64.so"
windows.debug.x86_64 = "res://bin/libmyextension.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libmyextension.windows.template_release.x86_64.dll"
macos.debug = "res://bin/libmyextension.macos.template_debug.framework"
macos.release = "res://bin/libmyextension.macos.template_release.framework"

The entry_symbol must exactly match the exported function name in your register_types.cpp. The library paths must point to where your build system outputs the compiled files. If the path is wrong, Godot cannot find the library and silently skips loading it. Check the Godot console output at startup for messages about failed GDExtension loads.

Hot Reload Issues

GDExtension supports hot reload so you can recompile and see changes without restarting the editor. This requires reloadable = true in the .gdextension file. However, hot reload has limitations.

Adding new classes, methods, or properties requires a full editor restart. Hot reload only updates the implementation of existing registered methods. If you add a new register_class call and recompile, the new class does not appear until you restart.

If hot reload stops working entirely, check that your build system is not outputting to a different path than what the .gdextension file specifies. Also verify the shared library is not locked by the editor. On Windows, the editor locks the DLL while running, and some build systems cannot overwrite it. Use a post-build copy step or configure your build to output to a temporary name that the extension loader can swap.

Related Issues

If your extension loads but crashes immediately, the most likely cause is a godot-cpp version mismatch. Always build godot-cpp from the branch that matches your Godot editor version. If methods are registered but not callable from GDScript, check that _bind_methods uses the correct D_METHOD signatures. For editor plugin classes, register at MODULE_INITIALIZATION_LEVEL_EDITOR instead of SCENE.

No error message means Godot never found your library. Check the .gdextension file paths first, then check the entry_symbol name.