Docs / SDK / Modules
Modules
A module bundles a workspace shell, entity types, inspectors, commands, and hotkeys into a self-contained unit. The workspace switcher lets users switch between modules like tabs.
Module definition
A ModuleDef is pure data -- no React, no side effects. It describes everything about a module: its workspace layout, entity types, commands, and hotkeys. Use the defineModule() builder to create one:
import { defineModule } from "@substrateui/substrate/modules";
import { workspaceShell, menuBar, toolBar, canvasSlot, dockZone, standardFileMenu } from "@substrateui/substrate/workspace";
import { entityType } from "@substrateui/substrate/entities";
const myModule = defineModule("inventory", "Inventory", {
icon: "package",
accent: "orange",
description: "Track products, stock levels, and warehouse locations.",
order: 4,
workspace: workspaceShell({
menuBar: menuBar([standardFileMenu()]),
canvas: canvasSlot("data-grid"),
dockZones: [
dockZone("left", [
{ id: "categories", label: "Categories", icon: "tags" },
], { defaultSize: 220 }),
],
}),
entities: [
entityType("product", {
name: "Product",
namePlural: "Products",
icon: "box",
accent: "orange",
module: "inventory",
displayField: "name",
statuses: [
{ id: "in-stock", label: "In Stock", color: "green", default: true },
{ id: "low-stock", label: "Low Stock", color: "yellow" },
{ id: "out-of-stock", label: "Out of Stock", color: "red" },
{ id: "discontinued", label: "Discontinued", color: "neutral", terminal: true },
],
}),
],
commands: [
{ id: "inventory.restock", label: "Restock", icon: "package-plus", category: "Inventory" },
{ id: "inventory.adjust", label: "Adjust Quantity", icon: "hash", category: "Inventory" },
],
hotkeys: [
{ id: "inventory.new-product", shortcut: "N", label: "New Product", commandId: "entity.create" },
],
});Module registry
Combine modules into a registry with createModuleRegistry(). The registry flattens all entity types, commands, and hotkeys across modules for cross-module lookup:
import { createModuleRegistry } from "@substrateui/substrate/modules";
import { financeModule, crmModule, projectMgmtModule } from "@substrateui/templates";
import { myModule } from "./my-module";
const registry = createModuleRegistry(
financeModule,
crmModule,
projectMgmtModule,
myModule,
);
// Access resolved registries
import { resolveEntityRegistry, resolveCommandRegistry } from "@substrateui/substrate/modules";
const entities = resolveEntityRegistry(registry);
// entities.typeById.get("contact") → EntityTypeDef
const commands = resolveCommandRegistry(registry);
// commands.byId.get("inventory.restock") → CommandDefBuilt-in templates
Substrate ships with 7 template modules that demonstrate real-world workspace patterns. Each is a complete ModuleDef you can use directly, extend, or use as a reference:
| Module | ID | Entities |
|---|---|---|
| Finance | finance | account, journal-entry, invoice, vendor, payment, budget, fund |
| CRM | crm | contact, company, deal, activity |
| Project Management | project-mgmt | project, task, sprint, milestone |
| Design Tool | design-tool | scene, asset, layer, component |
| Data Platform | data-platform | dataset, pipeline, query, notebook |
| Admin | admin | user, role, team, audit-log |
| Agent Ops | agent-ops | agent, workflow, run, skill, tool |
Import individual modules or use allTemplateModules to load all 7:
import { allTemplateModules } from "@substrateui/templates";
import { createModuleRegistry } from "@substrateui/substrate/modules";
// Load every template module
const registry = createModuleRegistry(...allTemplateModules);Registry helpers
Resolved registries flatten all definitions across modules into efficient lookup maps:
| Function | Returns |
|---|---|
| createModuleRegistry(...modules) | ModuleRegistry |
| resolveEntityRegistry(registry) | ResolvedEntityRegistry |
| resolveCommandRegistry(registry) | ResolvedCommandRegistry |
| resolveHotkeyRegistry(registry) | ResolvedHotkeyRegistry |
| getModule(registry, moduleId) | ModuleDef | undefined |
| getSortedModules(registry) | ModuleDef[] |