Overview
How a Kora module is laid out, how it loads and what it can hook into.
Everything Kora does at runtime comes from a module, including Core. Your own modules load the same way and get the same access to the database, API, dashboard, audit log and languages.
For installing and running Kora, see the Setup Guide.
Layout
Each folder in modules/ is one module. Kora imports its main.js and loads everything under src/ and resources/ by folder.
modules/
example/
main.js
resources/
config/
dashboard/
pages/
lang/
src/
clocks/
commands/
events/
handlers/
models/
routes/| Folder | Files loaded | Base class |
|---|---|---|
main.js | The module | Modules |
src/models/ | Every *.js | Models |
src/handlers/ | Every *.js | Handlers |
src/routes/ | Every route.js, at any depth | Routes |
src/clocks/ | Every *.js | Clocks |
src/events/ | Every *.js | Events |
src/commands/ | Every *.js | Commands |
resources/config/ | Every *.js | Configs |
resources/lang/ | en/*.js classes, plus a folder of JSON per locale | Langs |
resources/dashboard/pages/ | Every page.js, at any depth | Pages |
Import every base class from #kora/modules.
Loading
Kora loads modules in two passes.
- Register. Install any missing
dependencies.nodepackages, then read configs, languages, models, routes and pages. - Load. Start handlers, events, commands and clocks, call
onStartup(), sync tables and mount routes.
When Kora stops or a module is turned off, it stops clocks, removes events, calls onShutdown() and unmounts routes.
A module that throws while loading is marked as failed and shown on the Modules page. The others keep running.
main.js
import { Modules } from "#kora/modules";
export class Example extends Modules {
constructor(kora) {
super(kora, {
name: "example",
displayName: "Example",
author: "Your Name",
version: "1.0.0",
description: "Does one thing well",
icon: "box",
requires: ["core"],
dependencies: { node: ["nanoid"] }
});
}
async onStartup() {
this.kora.console.log(this.kora.console.levels.info, `${this.getName()} started.`);
}
}| Key | Default | What it does |
|---|---|---|
name | Required | The module ID. Use the folder name. |
displayName | name | Shown in the dashboard. |
author, version, description | None | Shown on the Modules page. |
icon | puzzle | A Lucide icon name. |
requires | [] | Modules that must load first. |
dependencies.node | [] | npm packages Kora installs before loading the module. |
Hooks
Add any of these methods to your module class.
| Method | Called |
|---|---|
onStartup() | After the module loads. |
onShutdown() | Before it unloads. |
permissions() | When Kora lists permissions. Return [{ id, label }]. They show up when editing roles. |
overview(actor) | When the Overview page loads. Return { stats, charts, lists }. |
search(query, actor) | When someone uses the dashboard search. Return [{ type, label, hint, href }]. |
fields(module, page) | When another module's page is described. Return extra form fields for it. |
decorate(module, page, rows) | When another module's page lists rows. Return the rows with your data added. |
overview and search only run for staff with the <module>.view permission.
Each entry in stats is { key, label, value, hint, icon, tone, period }. Set period to a number of days to show it as a badge in the card's corner instead of writing it into the label.
BuiltByBit uses fields and decorate to add a BuiltByBit resource picker to Core's product form:
fields(module, page) {
if (module !== "core" || page !== "products") return [];
return [{ key: "builtbybit_resource", label: "BuiltByBit resource", type: "reference", source: { module: "builtbybit", endpoint: "/resources", label: "title", value: "id" } }];
}The kora Object
Every class gets the running instance as this.kora.
| Property | What it is |
|---|---|
this.kora.database | The Sequelize connection. |
this.kora.settings | Values from the Settings page. |
this.kora.console | The logger. |
this.kora.audit | The audit log. |
this.kora.signer | Signs and checks payloads with the response signing key. |
this.kora.events | The event bus. See Events. |
this.kora.modules | Every loaded module and its parts. |
Reaching Other Modules
this.kora.modules.models.get("core", "licenses");
this.kora.modules.handlers.get("core", "licenses");
this.kora.modules.config.values("core", "licenses");
this.kora.modules.lang.phrase("core", "messages", "valid");