# How the hot_reloadable_module Facilitates Dynamic Code Updates in Equilibrium Engine

> Discover how the hot_reloadable_module in Equilibrium Engine enables dynamic code updates. Learn how it detects changes, unloads entities, and re-imports libraries without restart.

- Repository: [Alexander/equilibriumengine](https://github.com/clibequilibrium/equilibriumengine)
- Tags: internals
- Published: 2026-02-27

---

**The `hot_reloadable_module` component stores module metadata and plugin context, enabling the Equilibrium Engine to detect file changes via [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h), unload stale ECS entities, and re-import updated shared libraries without restarting the application.**

The Equilibrium Engine is an open-source ECS (Entity Component System) framework that leverages the `hot_reloadable_module` to achieve runtime code modification. By treating hot-reloadable systems as ECS entities, the engine can dynamically swap implementation code while preserving application state, dramatically accelerating iteration cycles during development.

## What Is the hot_reloadable_module?

The `hot_reloadable_module` is a specialized ECS component defined in [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h) that bridges the engine’s entity system with the underlying [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) hot-reloader library. It encapsulates two critical pieces of data:

- **`module_name`** – A string identifier for the shared library (e.g., `"PhysicsSystem"`).
- **`plugin_ctx`** – A pointer to the `cr_plugin` context managed by [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h), which tracks the DLL/SO handle and version state.

By storing this metadata as a component, the engine can query all hot-reloadable modules using ECS filters, enabling bulk cleanup when a file change is detected.

## How Dynamic Code Updates Work

The hot-reload lifecycle follows a strict registration-detection-cleanup-reimport pattern orchestrated by three core mechanisms.

### The Registration Phase (ECS_IMPORT_HOT_RELOADABLE)

When the host application starts (or after a reload), it invokes the `ECS_IMPORT_HOT_RELOADABLE(ctx, module)` macro. This macro, defined in [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h) (lines 81-95), performs three operations:

1. Resolves the module’s ECS import path.
2. Calls `ECS_IMPORT` to load the module’s symbols into the world.
3. Creates an ECS entity tagged with the `HotReloadableModule` component, storing the current `cr_plugin` pointer (`ctx`) and module name.

This registration links the logical module entity to the physical shared library file tracked by [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h).

### Detecting File Changes (cr.h Integration)

The Equilibrium Engine relies on [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) (located at [`3rdparty/cr/cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/3rdparty/cr/cr.h)) to monitor shared library timestamps. In the host’s main loop, `cr_plugin_update` is called continuously. When the underlying DLL or SO file is modified on disk, [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) returns the `CR_LOAD` operation code.

The engine detects this via the `CHECK_IF_PLUGIN_RELOADED(ctx, operation)` macro. When `operation == CR_LOAD`, the macro invokes `reload_modules(ctx)`, triggering the cleanup phase.

### The Cleanup and Re-import Cycle (reload_modules)

The `reload_modules` function (implemented in [`equilibrium/components/hot_reloadable_module.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.c)) queries the ECS for all entities possessing a `HotReloadableModule` component whose `plugin_ctx` matches the reloaded `cr_plugin` pointer. For each match:

1. It deletes the module’s entity using `ecs_delete`, which cascades to remove all associated components and systems.
2. It clears the stale `cr_plugin` context, ensuring no dangling pointers remain.

After cleanup completes, the host application calls `import_hot_reloadable_systems(ctx)` again (as seen in [`launcher/sandbox/main.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/launcher/sandbox/main.c)), which re-executes `ECS_IMPORT_HOT_RELOADABLE` for each module. This loads the newly compiled shared library, registers fresh systems, and creates new `HotReloadableModule` entities bound to the updated code.

## Implementation Example

The following pattern from [`launcher/sandbox/main.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/launcher/sandbox/main.c) demonstrates the complete integration:

```c
#include "cr.h"
#include "equilibrium/components/hot_reloadable_module.h"

static void import_hot_reloadable_systems(struct cr_plugin *ctx) {
    ECS_IMPORT_HOT_RELOADABLE(ctx, BootstrapSystem);
}

CR_EXPORT int cr_main(struct cr_plugin *ctx, enum cr_op operation) {
    if (operation == CR_CLOSE) return 0;

    static bool initialized = false;
    if (!initialized) {
        ECS_IMPORT(world, TransformSystem);
        import_hot_reloadable_systems(ctx);
        initialized = true;
    } else {
        CHECK_IF_PLUGIN_RELOADED(ctx, operation);
        import_hot_reloadable_systems(ctx);
    }
    return 0;
}

```

In this example, `BootstrapSystem` resides in a separate shared library. When the developer recompiles `BootstrapSystem.dll` (or `.so`), the running application detects the change, invokes `reload_modules` to purge the old system, and re-imports the new binary without losing the world state managed by `TransformSystem`.

## Key Files and Architecture

| File | Role |
|------|------|
| [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h) | Defines `HotReloadableModule` component, `ECS_IMPORT_HOT_RELOADABLE` macro, and `CHECK_IF_PLUGIN_RELOADED` macro |
| [`equilibrium/components/hot_reloadable_module.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.c) | Implements `reload_modules` function and component registration |
| [`launcher/sandbox/main.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/launcher/sandbox/main.c) | Example host application demonstrating import and reload detection |
| [`editor/editor.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/editor/editor.c) | Advanced host with multiple hot-reloadable modules |
| [`3rdparty/cr/cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/3rdparty/cr/cr.h) | Underlying C hot-reloader library providing `cr_plugin` context and `CR_LOAD` detection |

## Summary

- The `hot_reloadable_module` is an ECS component that stores module metadata and a pointer to the `cr_plugin` context, enabling the engine to track which entities belong to a specific shared library.
- **Dynamic code updates** are facilitated by the `ECS_IMPORT_HOT_RELOADABLE` macro, which registers modules, and the `reload_modules` function, which cleans up stale entities when [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) detects a file change.
- The system uses a detection-cleanup-reimport cycle: `CHECK_IF_PLUGIN_RELOADED` triggers on `CR_LOAD`, `reload_modules` purges old symbols via `ecs_delete`, and the host re-imports the new binary.
- Because hot-reloadable modules are regular ECS entities, the engine preserves world state and non-reloadable systems (like `TransformSystem`) while swapping only the targeted code.

## Frequently Asked Questions

### What triggers a dynamic code update in Equilibrium Engine?

A dynamic code update triggers when the `cr_plugin_update` function in [`3rdparty/cr/cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/3rdparty/cr/cr.h) detects that the timestamp or file size of the monitored shared library (DLL or SO) has changed. When this occurs, [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) returns the `CR_LOAD` operation code to the host’s `cr_main` function, which the `CHECK_IF_PLUGIN_RELOADED` macro intercepts to initiate the reload sequence.

### How does the engine prevent memory leaks during hot reloading?

The engine prevents memory leaks through the `reload_modules` function implemented in [`equilibrium/components/hot_reloadable_module.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.c). This function queries all ECS entities containing a `HotReloadableModule` component matching the reloaded plugin context and calls `ecs_delete` on each one. This deletion cascades through the ECS, automatically freeing all associated components, systems, and resources before the new module binary is imported.

### Can multiple modules be hot-reloaded simultaneously?

Yes, multiple modules can be hot-reloaded simultaneously because each is tracked as a distinct ECS entity with its own `HotReloadableModule` component. The `reload_modules` function filters entities by the specific `cr_plugin` pointer passed to it, allowing the host to manage separate plugin contexts (e.g., `PhysicsSystem` and `RenderingSystem` as separate DLLs). When a file change is detected in any monitored library, only the entities associated with that specific plugin context are cleaned up and re-imported.

### What is the role of cr.h in the hot_reloadable_module system?

The [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h) library (located at [`3rdparty/cr/cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/3rdparty/cr/cr.h)) serves as the underlying C hot-reloader that manages the shared library lifecycle. It provides the `cr_plugin` structure for context tracking, the `cr_plugin_update` function for polling file changes, and the `CR_LOAD` operation code that signals a reload event. The `hot_reloadable_module` system acts as an ECS abstraction layer over [`cr.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/cr.h), converting low-level plugin events into entity lifecycle operations that integrate with the engine’s component system.