# How to Create a New Extension Class That Inherits From Built-In Godot Classes in gdext-nim

> Learn to create new extension classes inheriting from Godot classes in gdext-nim. Define Nim types, annotate with gdsync, and register them in your bootstrap file.

- Repository: [godot-nim 4+/gdext-nim](https://github.com/godot-nim/gdext-nim)
- Tags: how-to-guide
- Published: 2026-03-02

---

**To create a new extension class that inherits from built-in Godot classes, define a Nim type as a `ptr object of Node` (or any engine class), annotate it with `{.gdsync.}`, and register it in your bootstrap file to expose it to the engine.**

The gdext-nim library (available at `godot-nim/gdext-nim`) provides a type-safe Nim interface to the GDExtension API. Creating a new extension class that inherits from built-in Godot classes involves using specific pragmas that handle binding registration, property exposure, and lifecycle callbacks automatically.

## Project Setup and Class Scaffolding

Start by generating a new extension project using the CLI wizard. The `gdextwiz new-extension` command creates a skeleton project including a `src/bootstrap.nim` registration file and template classes.

According to the wizard source in [`src/gdext/wizard/subcommands/extension.nim`](https://github.com/godot-nim/gdext-nim/blob/for-4.6-stable/src/gdext/wizard/subcommands/extension.nim), the generated template includes a ready-made example class at `src/classes/gdmyclass.nim` that demonstrates the inheritance pattern.

## Defining the Extension Class

Create a new Nim file in `src/classes/` and define your type with the `{.gdsync.}` pragma. This pragma, implemented in [`src/gdext/private/userclass/procs.nim`](https://github.com/godot-nim/gdext-nim/blob/for-4.6-stable/src/gdext/private/userclass/procs.nim), marks the type for engine registration and generates the necessary glue code.

```nim

# src/classes/gdmyclass.nim

import gdext
import gdext/classes/gdNode  # Import the built-in class you want to inherit from

type MyClass* {.gdsync.} = ptr object of Node
  message* {.gdexport.}: string = "This is MyClass."
  address: uint64

```

Key components of this definition:

- **`ptr object of Node`** — Declares inheritance from the built-in `Node` class (defined in [`src/gdext/classes/gdnode.nim`](https://github.com/godot-nim/gdext-nim/blob/for-4.6-stable/src/gdext/classes/gdnode.nim)). You can substitute `Node` with any engine class like `Sprite2D` or `CharacterBody2D` by importing the corresponding `gdext/classes/gdSprite2D` module.
- **`{.gdsync.}`** — Required pragma that exposes the type and its members to Godot's ClassDB.
- **`{.gdexport.}`** — Makes the field visible as a property in the Godot editor inspector.

## Implementing Methods, Signals, and Lifecycle Callbacks

Define methods using Nim's `method` syntax combined with the `{.gdsync.}` pragma to implement Godot's virtual callbacks like `_ready` and `_process`.

```nim

# Lifecycle callbacks

method ready(self: MyClass) {.gdsync.} =
  echo "MyClass is ready"

method process(self: MyClass; delta: float) {.gdsync.} =
  # Per-frame logic here

  discard

```

For **signals**, declare a proc with the `{.signal.}` pragma. The return type must be `Error`, and you emit the signal by calling the proc:

```nim
proc mySignal(self: MyClass): Error {.gdsync, signal.}

method ready(self: MyClass) {.gdsync.} =
  assert self.mySignal() == ok  # Emit the signal

```

To expose **custom getters and setters** for properties, define procs with `{.gdsync.}` and bind them using `gdexport`:

```nim
proc address_readable(self: MyClass): string {.gdsync, name: "get_address_readable".} =
  self.address.toHex.insertSep(' ', 4)

gdexport "address_readable",
  address_readable,
  proc (self: MyClass; value: string) = (discard)  # Setter (optional)

```

Note that `onInit` can serve as a constructor-style hook for initialization logic, but it does **not** require `{.gdsync.}` because it operates outside the GDExtension API boundary.

## Registering the Class with Godot

Every extension class must be registered in the bootstrap file to be recognized by the engine. The generated `src/bootstrap.nim` contains a `register_classes` proc executed at the `initialize_scene` level.

```nim

# src/bootstrap.nim

import gdext
import classes/gdmyclass

proc register_classes {.execon: initialize_scene.} =
  register MyClass  # <-- Add your class here

```

The `register` template, defined in the core [`gdext.nim`](https://github.com/godot-nim/gdext-nim/blob/for-4.6-stable/src/gdext.nim) and utilizing [`src/gdext/private/classindex.nim`](https://github.com/godot-nim/gdext-nim/blob/for-4.6-stable/src/gdext/private/classindex.nim), stores the class metadata in Godot's ClassDB at the specified initialization level.

## Complete Working Example

Below is a minimal, self-contained class inheriting from `Sprite2D` that moves right every frame:

```nim

# src/classes/gdplayer.nim

import gdext
import gdext/classes/gdSprite2D
import std/math

type Player* {.gdsync.} = ptr object of Sprite2D
  speed* {.gdexport.}: float = 300

method ready(self: Player) {.gdsync.} =
  echo "Player ready with speed: ", self.speed

method process(self: Player; delta: float) {.gdsync.} =
  self.position.x += self.speed * delta

```

Register it in `src/bootstrap.nim`:

```nim
import gdext
import classes/gdplayer

proc register_classes {.execon: initialize_scene.} =
  register Player

```

Build and run using the CLI:

```bash
gdextwiz run

```

The command compiles the Nim code into a GDExtension library, copies it to your Godot project, and launches the editor. The `Player` node will appear in the editor with an exposed **Speed** property.

## Summary

- **Inheritance** — Use `ptr object of Node` (or any built-in class from `gdext/classes/`) to extend engine functionality.
- **Exposure** — Apply `{.gdsync.}` to types and methods, and `{.gdexport.}` to fields you want visible in the editor.
- **Lifecycle** — Implement `ready`, `process`, and other virtuals as Nim methods with `{.gdsync.}`.
- **Registration** — Call `register YourClass` inside the `register_classes` proc in `bootstrap.nim` marked with `{.execon: initialize_scene.}`.
- **CLI Workflow** — Use `gdextwiz new-extension` to scaffold and `gdextwiz run` to build and test.

## Frequently Asked Questions

### How do I choose which built-in Godot class to inherit from?

Import the corresponding module from `gdext/classes/` (e.g., `import gdext/classes/gdCharacterBody2D`) and declare your type as `ptr object of CharacterBody2D`. The inheritance chain follows Godot's native hierarchy exactly, so inheriting from `Node` gives you scene tree participation, while `Node2D` or `Node3D` adds spatial properties.

### What is the difference between `{.gdsync.}` and `{.gdexport.}`?

`{.gdsync.}` is a type or method-level pragma that registers the symbol with Godot's extension system (handled in `private/userclass/procs.nim`), enabling the engine to instantiate and call it. `{.gdexport.}` is a field-level annotation that generates property bindings for the editor inspector, creating getters and setters automatically unless you provide custom ones.

### Why does my class need to be a `ptr object`?

Godot's GDExtension API manages object lifecycles through pointers. The `ptr object` allocation model ensures memory compatibility with the engine's reference counting system. The `gdsync` macro generates the necessary boilerplate to handle reference counting and pointer safety automatically.

### How do I expose a property with custom getter and setter logic?

Define a proc with `{.gdsync.}` and an explicit `name` pragma (e.g., `name: "get_custom"`), then bind it using the `gdexport` macro with the property name, getter proc, and an optional setter proc. This pattern is demonstrated in the template `gdmyclass.nim` and allows you to transform internal data (like converting a `uint64` address to a readable hex string) while maintaining editor visibility.