AponiaJSDocs
Essentials

Modules

Group controllers and providers into explicit dependency and visibility boundaries.

@Module() accepts four arrays:

import { Module } from "@aponiajs/common";

@Module({
  imports: [],
  controllers: [],
  providers: [],
  exports: [],
})
export class FeatureModule {}
FieldMeaning
importsOther decorated, dynamic, or low-level modules this module consumes.
controllersDecorated controller classes owned by this module.
providersClass providers or explicit provider descriptors.
exportsProvider tokens visible to importing modules.

Metadata arrays are copied and frozen when the decorator runs.

Import only what you consume

@Module({
  providers: [GreetingService],
  exports: [GreetingService],
})
export class GreetingModule {}

@Module({
  imports: [GreetingModule],
  controllers: [AppController],
})
export class AppModule {}

An import alone does not expose every provider. The imported module must list the consumed token in exports.

Validation before startup

The graph compiler rejects:

  • module import cycles;
  • different module definitions with the same identity;
  • duplicate provider tokens inside one module;
  • missing or ambiguous dependencies;
  • exports that cannot be resolved;
  • duplicate controllers and missing controller dependencies.

This validation happens before the application begins listening.

Low-level definitions

Framework adapters can use defineModule() instead of decorators:

import { defineModule } from "@aponiajs/common";

const AppModule = defineModule({
  id: "AppModule",
  providers: [],
  controllers: [],
});

Application code should normally prefer @Module(). See Low-level descriptors.

On this page