Skip to content

Module lifecycle

Modules in Zumito Framework expose lifecycle hooks that allow you to execute code at specific moments during the bot’s initialization.

Modules can declare dependencies on other modules using static properties. The framework resolves these dependencies and loads modules in the correct order using topological sorting (dependencies first).

Each module can declare its own name, which is used for dependency resolution:

import { Module } from 'zumito-framework';
export class MyModule extends Module {
static moduleName = 'my-module';
}

If moduleName is not declared, the folder name is used as the module name.

Declare required dependencies — modules that must be loaded before this one:

import { Module } from 'zumito-framework';
export class MyModule extends Module {
static dependencies = ['logger-module', 'admin-module'] as const;
}

If a required dependency is not found, the module will not be loaded and an error is logged.

Declare optional dependencies — modules that should be loaded first if present, but will not prevent loading if absent:

import { Module } from 'zumito-framework';
export class MyModule extends Module {
static optionalDependencies = ['sentry'] as const;
}

The legacy requeriments.modules property is still supported and is merged with the dependencies array:

export class MyModule extends Module {
static requeriments = {
modules: ['admin-module'],
services: [],
custom: [],
};
}

Circular dependencies are detected and reported as errors. The affected modules are skipped during loading:

[📦❌] Circular dependency detected involving: ModuleA, ModuleB

This method is called automatically when the module is loaded. It handles:

  • Loading commands from the commands/ folder
  • Registering events from the events/ folder
  • Loading translations from the translations/ folder
  • Registering routes from the routes/ folder

You can override it if you need custom initialization logic, but make sure to call super.initialize():

import { Module } from 'zumito-framework';
export class MyModule extends Module {
async initialize() {
await super.initialize();
// Custom initialization code
}
}

This hook is called after the entire framework is ready — Discord client connected, all modules loaded, slash commands refreshed, and API server started. It is the ideal place for code that depends on the bot being fully operational.

import { Module } from 'zumito-framework';
export class MyModule extends Module {
async onAllReady() {
// Bot is fully ready
console.log(`Logged in as ${this.framework.client.user?.tag}`);
}
}

As an alternative, you can listen to the ready event emitted by the framework emitter. This is useful when you want to react from an event class without touching the module class:

import { FrameworkEvent } from 'zumito-framework';
export class OnFrameworkReady extends FrameworkEvent {
source = 'framework';
once = true;
async execute(): Promise<void> {
console.log('Framework is ready!');
}
}
  1. Discord client connects and emits ready
  2. All module classes are loaded and their dependencies are resolved
  3. Modules are topologically sorted (dependencies first)
  4. Each module is instantiated in sorted order
  5. Each module’s initialize() is called in sorted order
  6. Slash commands are refreshed
  7. API server starts
  8. Framework ready event is emitted
  9. Each module’s onAllReady() is called
  10. User callback (configured in zumito.config.ts) is executed