modules/<name>/. Running ooneex module:create scaffolds a fixed set of files: a definition that lists the module’s artifacts, a config file, a workspace package.json, a tsconfig.json, and a mirrored test. Everything you generate afterward — controllers, entities, services, middleware — lands in predictable subfolders under src/. This page walks through that layout file by file.
See Overview for what a module is and Composition for how modules combine.
Layout
A freshly createdbilling module looks like this:
src/ (controllers/, services/, repositories/, entities/, middlewares/) are created on demand as you generate artifacts into the module — a new module starts with just src/<Pascal>Module.ts. The bin/ folder is optional and holds seeds and runnable commands for modules that need them.
Generated files
src/<Pascal>Module.ts — the module definition
The heart of the module. It exports a single ModuleType object whose arrays declare what the module contributes to the application. You register each artifact you create by adding it to the matching array.
src/ subfolder where those artifacts live:
ModuleType array | Artifact | Lives under |
|---|---|---|
controllers | HTTP / WebSocket controllers | src/controllers/ |
entities | Database entities | src/entities/ |
middlewares | Request middleware | src/middlewares/ |
cronJobs | Scheduled jobs | src/ (cron job classes) |
events | Event listeners | src/ (event classes) |
src/services/ and src/repositories/ without a dedicated ModuleType array. See Controller and Entity for those artifact types, and Middleware for the middleware pipeline.
<name>.yml — module config
Declares the module’s type. The generator writes type: "module":
type is one of api, microservice, design, spa, sdk, or module, depending on what kind of unit you scaffold.
package.json — workspace package
Each module is its own workspace package named @module/<name>. It starts at version 0.0.1 and ships test and lint scripts:
@module/billing package name doubles as the import-path alias once it is registered in the root tsconfig.json (see Registration).
tsconfig.json
The module’s TypeScript configuration, extending the workspace defaults.
tests/<Pascal>Module.spec.ts — the mirrored test
Every module ships a test that mirrors the definition and asserts each ModuleType array exists. It guards against a malformed definition — checking that controllers, entities, middlewares, cronJobs, and events are all present on the exported module object. Run it with the package’s test script (bun test tests).
Core modules: app and shared
Two modules are special and exist in every project:
| Module | Role |
|---|---|
app | The application root. It composes the other modules and is the default destination for generated artifacts that belong to the running app. |
shared | Cross-cutting code reused across modules — shared services, middleware, and utilities. It is the default target for several generators (for example, middleware:create defaults to shared). |
app destination, the generator registers it into both AppModule and SharedModule so its artifacts are wired into the application and available to other modules.
Registration
Creating a module is not just file generation —module:create also wires the module into the project:
- Registers the module into its destination. For the
appdestination, it adds the module toAppModuleandSharedModule. - Adds the path alias. The
@module/<name>import alias is added to the roottsconfig.json, so other code can import the module by its package name. - Adds the commit scope. When a
.commitlintrc.tsis present, the module’s scope is added so commits can be scoped to the module.
Next steps
- Overview — what a module is and why modules exist.
- Composition — how modules are combined into an application.
- Create — the
module:createcommand reference. - Controller and Entity — the artifacts you register in the definition.
- Middleware — the request pipeline a module contributes to.