> For the complete documentation index, see [llms.txt](https://boxlang.ortusbooks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://boxlang.ortusbooks.com/boxlang-framework/module-development/lifecycle.md).

# Lifecycle

Complete module lifecycle from discovery through registration, activation, and deactivation

BoxLang modules follow a well-defined lifecycle with distinct phases, each firing events that your module can listen to.

## Lifecycle Overview

```mermaid
graph TD
    A[Discovery] --> B[Registration]
    B --> C[Activation]
    C --> D[Running]
    D --> E[Deactivation]
    E --> F[Unloaded]

    B --> |interceptors registered| B1[PRE_MODULE_REGISTRATION]
    B --> |BIFs, components, services loaded| B2[POST_MODULE_REGISTRATION]
    C --> |nested modules, then dependencies, activated first| C1[PRE_MODULE_LOAD]
    C --> |onLoad() called| C2[POST_MODULE_LOAD]
    E --> |nested modules unloaded first| E1[PRE_MODULE_UNLOAD]
    E --> |onUnload() called, cleanup complete| E2[POST_MODULE_UNLOAD]
```

{% hint style="info" %}
A module carrying modules of its own runs this whole lifecycle for each child first. Children register and activate **before** their parent, and unload **after** it. See [Module Inception](/boxlang-framework/module-development/module-inception.md).
{% endhint %}

## Phase 1: Discovery

When the runtime starts, the `ModuleService` scans configured paths for directories containing `ModuleConfig.bx` or `box.json`, and for `*.jar` files, which are modules in their own right.

**What happens:**

* Each discovered module becomes a `ModuleRecord` in the registry
* Duplicates are resolved first-come-first-served
* Module name is determined from `box.json` `boxlang.moduleName`, a JAR's `@BoxModule( name )`, or the directory / JAR base name
* Each discovered module is then scanned for a `modules/` folder of its own, recursively — see [Module Inception](/boxlang-framework/module-development/module-inception.md)

**No events fire during discovery.**

## Phase 2: Registration

Each module is registered in the order discovered. Registration loads the descriptor and prepares the module but does **not** make it active.

{% stepper %}
{% step %}

### PRE\_MODULE\_REGISTRATION Event

Fires before the module descriptor is loaded. The `moduleRecord` and `moduleName` are available in the event data.

```js
function preModuleRegistration( event ) {
    var moduleName = event.getData().moduleName
    log.info( "About to register: #moduleName#" )
}
```

{% endstep %}

{% step %}

### Load Descriptor

The descriptor (`ModuleConfig.bx` or Java `IModuleConfig`) is loaded. The module's class loader is created with isolation from other modules.
{% endstep %}

{% step %}

### Configure the Module

The `configure()` method is called:

* Module `settings` struct is populated
* Interceptors are registered from the `interceptors` array
* Custom interception points are added
  {% endstep %}

{% step %}

### Discover Capabilities

Auto-discovery scans for:

* `bifs/` → BoxLang BIF files compiled and registered
* `components/` → BoxLang components registered
* ServiceLoader entries → Java BIFs, components, services, schedulers, cache providers
* `public/` → Public web folder mapping
  {% endstep %}

{% step %}

### POST\_MODULE\_REGISTRATION Event

Fires after the module is fully registered. All module capabilities are available.
{% endstep %}
{% endstepper %}

**After all modules are registered**, the `AFTER_MODULE_REGISTRATIONS` event fires.

## Phase 3: Activation

Activation makes the module "live" in the runtime. Dependencies are activated first (recursively).

{% stepper %}
{% step %}

### Resolve Dependencies

Dependencies declared in `this.dependencies` are activated in order before this module.
{% endstep %}

{% step %}

### PRE\_MODULE\_LOAD Event

Fires before `onLoad()` is called. All dependencies are already active at this point.
{% endstep %}

{% step %}

### onLoad() Called

The `onLoad()` lifecycle method executes. This is where you:

* Register system setting providers
* Register custom class resolvers
* Modify runtime configuration
* Initialize module state
* Check for other loaded modules
  {% endstep %}

{% step %}

### POST\_MODULE\_LOAD Event

Fires after `onLoad()` completes successfully.
{% endstep %}
{% endstepper %}

**After all modules are activated**, the `AFTER_MODULE_ACTIVATIONS` event fires, followed by `ON_MODULE_SERVICE_STARTUP`.

## Phase 4: Running

The module is active and all its capabilities are available to the runtime:

* BIFs are callable from BoxLang code
* Components are usable as `bx:` tags
* Interceptors are listening for events
* Services are available via `BoxRuntime`

## Phase 5: Deactivation (Shutdown)

When the runtime shuts down or a module is explicitly unloaded:

{% stepper %}
{% step %}

### ON\_MODULE\_SERVICE\_SHUTDOWN Event

Fires when the module service begins shutdown.
{% endstep %}

{% step %}

### PRE\_MODULE\_UNLOAD Event

Fires before `onUnload()` is called.
{% endstep %}

{% step %}

### onUnload() Called

The `onUnload()` lifecycle method executes. Clean up:

* Unregister system setting providers
* Unregister class resolvers
* Close connections and resources
* Remove any runtime modifications

{% hint style="warning" %}
Always wrap `onUnload()` cleanup in try/catch blocks. If one module's cleanup fails, it shouldn't prevent other modules from unloading.
{% endhint %}
{% endstep %}

{% step %}

### Cleanup

The module service automatically:

* Unregisters all interceptors
* Unregisters JDBC drivers
* Removes global services
* Unregisters mappings
* Closes the module class loader
  {% endstep %}

{% step %}

### POST\_MODULE\_UNLOAD Event

Fires after cleanup is complete.
{% endstep %}
{% endstepper %}

## Lifecycle Events Reference

| Event                        | Phase        | Data                         |
| ---------------------------- | ------------ | ---------------------------- |
| `PRE_MODULE_REGISTRATION`    | Registration | `moduleRecord`, `moduleName` |
| `POST_MODULE_REGISTRATION`   | Registration | `moduleRecord`, `moduleName` |
| `AFTER_MODULE_REGISTRATIONS` | Registration | `moduleRegistry`             |
| `PRE_MODULE_LOAD`            | Activation   | `moduleRecord`, `moduleName` |
| `POST_MODULE_LOAD`           | Activation   | `moduleRecord`, `moduleName` |
| `AFTER_MODULE_ACTIVATIONS`   | Activation   | `moduleRegistry`             |
| `ON_MODULE_SERVICE_STARTUP`  | Activation   | `moduleService`              |
| `ON_MODULE_SERVICE_SHUTDOWN` | Deactivation | `moduleService`              |
| `PRE_MODULE_UNLOAD`          | Deactivation | `moduleRecord`, `moduleName` |
| `POST_MODULE_UNLOAD`         | Deactivation | `moduleRecord`, `moduleName` |

## Listening to Events

Your `ModuleConfig.bx` can listen to any lifecycle event by defining a matching method:

```js
class {
    // Called when any module finishes loading
    function postModuleLoad( event ) {
        var moduleName = event.getData().moduleName
        log.info( "Module loaded: #moduleName#" )
    }

    // Called when all modules are active
    function onModuleServiceStartup( event ) {
        log.info( "All modules are ready!" )
        initializeIntegrations()
    }
}
```

{% hint style="info" %}
Your module config file is also registered as an interceptor automatically, so any runtime event method you define will be called.
{% endhint %}

## Version Compatibility

During registration, the module's `minimumVersion` (from `box.json`) is checked against the running BoxLang version using semver:

* **Major version lower** → Module is rejected with an error
* **Minor/patch version lower** → Module loads but logs a warning

{% hint style="info" %}
In development mode (BoxLang version `0.x.x`), version checks are skipped entirely.
{% endhint %}

## Next Steps

* [Capabilities](/boxlang-framework/module-development/capabilities.md) — Learn what modules can provide
* [Configuration](/boxlang-framework/module-development/configuration.md) — Settings and runtime overrides
* [Advanced Collaboration](/boxlang-framework/module-development/advanced-collaboration.md) — System settings providers and class resolvers


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://boxlang.ortusbooks.com/boxlang-framework/module-development/lifecycle.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
