# How to Create Custom Properties That Appear in the Godot Inspector Using gdext-nim

> Learn how to create custom properties in the Godot Inspector using gdextnim. Add exported fields to your Nim classes and control their appearance for custom editors.

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

---

**Use the `{.gdexport.}` pragma on Nim class fields and optionally pass an `Appearance` value from `gdext/appearances.nim` to control which editor widget Godot renders in the Inspector.**

The `godot-nim/gdext-nim` repository provides a Nim-to-GDExtension binding that lets you write Godot 4 game logic in Nim while maintaining full editor integration. When you create custom properties that appear in the Godot inspector, the library automatically bridges Nim field definitions to Godot's `PropertyInfo` system, enabling visual editing without writing boilerplate registration code.

## How Property Registration Works

The `gdext` bridge implements a three-stage pipeline that converts Nim pragmas into Godot inspector entries:

1. **`src/gdext/bridge.nim`** (lines 260–320) – Exports the public `gdexport` templates and macros that you write in your class definitions.
2. **`src/gdext/private/internalbridge.nim`** (lines 196–240) – Implements `gdexport_internal`, which inspects the `gdexport` pragma, extracts optional `Appearance` metadata, builds a Godot `PropertyInfo` structure, and registers the property with the engine.
3. **`src/gdext/appearances.nim`** – Defines the `Appearance` helper type and constructors (`range`, `enum`, `file`, `multiline`, etc.) that map to specific Godot inspector widgets.

When the Nim compiler processes your class, `internalbridge.nim` iterates over all fields (`for field in classInfo.fields`). If a field carries the `gdexport` pragma, the bridge checks for an optional argument via `field.getPragmaVal("gdexport")`. The extracted value—an `Appearance` instance—determines the widget type, validation limits, and display hints that Godot uses when rendering the property panel.

## Exporting Basic Properties

To expose a field to the editor with the default widget for its type, annotate the field with `{.gdexport.}` and ensure it is exported from the Nim module using the `*` postfix:

```nim
import gdext

gdclass MyNode of Node:
  counter* {.gdexport.}: int = 0

```

This registers `counter` as a read/write property in the Godot Inspector, appearing as a standard integer spin-box.

## Controlling Editor Appearance

For specialized widgets, import `gdext/appearances` and pass an `Appearance` constructor to the pragma:

### Numeric Inputs with Ranges

Use `Appearance.range` to replace the spin-box with a slider and define hard limits or soft boundaries:

```nim
import gdext, gdext/appearances

gdclass MyNode of Node:
  health* {.gdexport: Appearance.range(0, 100, step = 5).}: int = 50
  damage* {.gdexport: Appearance.range(min = 10, max = 100, step = 5, or_less, or_greater).}: int = 20

```

The `or_less` and `or_greater` flags allow users to input values outside the slider range while keeping the visual guide intact.

### Enum Dropdowns and Flag Sets

Export Nim enums as dropdown selectors or bitmask checklists:

```nim
import gdext, gdext/appearances

type
  Weapon = enum
    Sword, Bow, Axe
  Ability = enum
    Jump, Run, Fly

gdclass MyNode of Node:
  # Dropdown selector

  weapon* {.gdexport: Appearance.enum("Sword", "Bow", "Axe").}: Weapon = Weapon.Sword
  
  # Bitmask checklist (set[Enum])

  abilities* {.gdexport: Appearance.flags("Jump", "Run", "Fly").}: set[Ability] = {}

```

### File and Directory Pickers

Trigger native file dialogs with extension filters or directory selection:

```nim
import gdext, gdext/appearances

gdclass MyNode of Node:
  scriptFile* {.gdexport: Appearance.file("*.txt;*.nim").}: String = ""
  dataFolder* {.gdexport: Appearance.dir.}: String = ""

```

### Multiline Text and Placeholders

For long text fields, enable the multiline editor and add placeholder hints:

```nim
import gdext, gdext/appearances

gdclass MyNode of Node:
  description* {.gdexport: Appearance.multiline.}: String = "Default description text"
  secretCode* {.gdexport: Appearance.placeholder("Enter activation code...").}: String = ""

```

## Organizing Properties with Categories

Use the `gdexport` macro to group related fields under collapsible sections in the Inspector:

```nim
import gdext

gdclass MyNode of Node:
  gdexport[MyNode] "Combat Settings", Appearance.category:
    attackPower* {.gdexport.}: int = 10
    defense* {.gdexport.}: int = 5

```

This creates a "Combat Settings" header in the Godot Inspector containing the two fields, improving editor organization for complex nodes.

## Complete Working Example

The test suite at `testproject/editor/nim/src/classes/gdproptestnode_pragmas.nim` demonstrates every supported editor hint in a single class:

```nim
import gdext, gdext/appearances

gdclass PropTestNode of Node:
  icon* {.gdexport.}: gdref Texture2D
  string_with_export* {.gdexport.}: string = "with export"
  string_with_export_placeholder* {.gdexport: Appearance.placeholder("placeholder here...").}: string
  int_with_export_range* {.gdexport: Appearance.range(min = 10, max = 100, step = 5, or_less, or_greater).}: int = 20
  color_with_export* {.gdexport.}: Color = color(1, 1, 1, 0.5)
  node_path* {.gdexport(Appearance.nodePath("Node2D", "Node3D")).}: NodePath

```

This class exposes textures, ranged integers, colors, and typed node paths, each rendering with the appropriate native Godot widget.

## Summary

- **Annotation**: Add `{.gdexport.}` to any exported Nim field (`*`) to register it with Godot.
- **Appearance**: Import `gdext/appearances` and pass `Appearance.range`, `Appearance.enum`, `Appearance.file`, or other helpers to customize the inspector widget.
- **Registration**: The bridge in `src/gdext/private/internalbridge.nim` handles `PropertyInfo` creation and engine registration automatically at compile time.
- **Organization**: Use the `gdexport` macro with `Appearance.category` to create collapsible groups in the Inspector panel.

## Frequently Asked Questions

### What is the difference between the `gdexport` pragma and the `gdexport` macro?

The `{.gdexport.}` pragma registers individual fields with optional appearance metadata, while the `gdexport[ClassName] "Group Name", Appearance.category:` macro creates logical groupings that wrap multiple fields under a collapsible Inspector section. Use the pragma for data exposure and the macro for UI organization.

### How do I create a ranged slider for float values instead of integers?

The `Appearance.range` constructor works for any numeric type. Specify float literals in the arguments, and Godot will render a float slider:

```nim
speed* {.gdexport: Appearance.range(0.0, 100.0, step = 0.1).}: float = 10.0

```

### Can I restrict NodePath exports to specific node types?

Yes. Pass valid class names to `Appearance.nodePath` to filter the node selection dialog:

```nim
targetSprite* {.gdexport: Appearance.nodePath("Sprite2D", "AnimatedSprite2D").}: NodePath

```

Only nodes inheriting from the specified types will be selectable in the editor's node picker.

### Where is the low-level property binding logic implemented?

The core registration logic resides in `src/gdext/private/internalbridge.nim`, specifically in the `gdexport_internal` procedure (around line 196) and the pragma-inspection loop (around line 227) that iterates through class fields and constructs the Godot `PropertyInfo` objects.