---
title: Registry
description: How modules are auto-discovered and their configs cached for runtime access.
---

The **Registry** is Nibiru's module-config cache. At boot it walks every directory under `application/module/`, parses each module's `settings/*.ini`, and exposes the parsed config through a single accessor. Think of it as the gravitational centre that keeps modules in orbit around each other.

## How discovery works

For each module under `application/module/<name>/settings/`:

1. The Registry iterates files matching `*.ini`.
2. For each, it tries the **environment-specific** filename first (`<base>.<env>.<ext>`, e.g. `users.production.ini`); falls back to the base name (`users.ini`).
3. It calls `parse_ini_file($path, true)` (multi-section).
4. It looks for a section named after the module, *uppercased* — `[USERS]`, `[CMS]`, `[ANALYTICS]`.
5. The parsed key/value pairs become an `\stdClass` keyed by the module name.

## Reading a module's config

```php
$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');
$users->session_lifetime;
$users->password_min_length;
$users->allowed_roles;        // array
```

Inside the module itself the convention is to wrap this in a setter:

```php
class Users extends ModuleAdapter implements IModule
{
    const CONFIG_MODULE_NAME = 'users';
    protected static \stdClass $usersRegistry;

    protected function setUsersRegistry(): void {
        self::$usersRegistry = Registry::getInstance()
            ->loadModuleConfigByName(self::CONFIG_MODULE_NAME);
    }

    public static function lifetime(): int {
        return (int) self::$usersRegistry->session_lifetime;
    }
}
```

## Why uppercase section names?

INI section names are conventionally uppercased to make them visually distinct. The Registry assumes this, so a module called `cms` looks for `[CMS]`. Always uppercase.

## Multi-INI per module

Nothing stops you from having more than one INI file in a module's `settings/` folder. The Registry parses them all and merges everything matching `[<MODULE>]` into the same `\stdClass`. Useful for splitting concerns:

```
application/module/users/settings/
├── users.ini              # [USERS] base config
├── users.smtp.ini         # [USERS] mail-related keys
└── users.production.ini   # production override
```

## When to use the Registry vs Config

| | `Config` | `Registry` |
|---|---|---|
| Source | `settings.<env>.ini` (one file) | per-module INIs (many files) |
| Scope | app-wide framework config | module-specific config |
| Sections | mixed (DATABASE, SETTINGS, ENGINE…) | one per module |
| Lookup | `Config::getInstance()->getConfig()['DATABASE']['driver']` | `Registry::getInstance()->loadModuleConfigByName('users')` |

A module that needs to read `[DATABASE] driver` reaches for `Config`. A module that needs to read its own `[USERS] session_lifetime` reaches for `Registry`.

## Listing all loaded modules

```php
$registry = \Nibiru\Registry::getInstance();
foreach ($registry->getModuleNames() as $name) {
    $cfg = $registry->loadModuleConfigByName($name);
    echo "$name → " . print_r($cfg, true) . "\n";
}
```

Useful in a debug controller or admin dashboard.

## Reload semantics

Like `Config`, the Registry is a singleton populated **once** per request. If you change a module's INI you need to refresh the request to see the new values. There's a `destroy()` method on the Registry singleton if you really need to reload mid-request, but in normal flows you won't.

## Common pitfalls

- **Section name doesn't match the module folder.** Folder `users/`, expected section `[USERS]`. Mismatch → empty config.
- **INI file extension.** Only `*.ini` is parsed. A `*.conf` or `*.config` file is ignored.
- **Environment file beats base file silently.** If `users.production.ini` exists with `[USERS]` it shadows `users.ini` entirely — not merged. Keep both files in sync, or use one + an overlay.
