Skip to Content
OverviewModules

Modules

A module is a class annotated with @Module(). The decorator provides metadata that Austial uses to organize the application structure.

from austial import Module from .cats_controller import CatsController from .cats_service import CatsService @Module( controllers=[CatsController], providers=[CatsService], ) class CatsModule: pass
PropertyMeaning
importsOther modules whose exported providers this module needs.
controllersControllers defined in this module, instantiated by Austial.
providersProviders registered by this module, resolvable within it (and, currently, application-wide — see the note below).
exportsThe subset of providers (or re-exported imported tokens) other modules can use once they import this module.

The root module

Every Austial app has at least one root module, conventionally AppModule, which AustialFactory.create() starts scanning from:

from austial import Module from austial.common.middleware import LoggingMiddleware, MiddlewareConsumer from austial.config import ConfigModule from .app_controller import AppController from .app_service import AppService from .modules.health.health_module import HealthModule @Module( imports=[ConfigModule.for_root(), HealthModule], controllers=[AppController], providers=[AppService], ) class AppModule: def configure(self, consumer: MiddlewareConsumer) -> None: consumer.apply(LoggingMiddleware).for_routes("*")

AustialFactory.create(AppModule) walks this imports graph recursively (austial.core.module_scanner.scan_module), registering every module’s controllers/providers into one shared Container, and de-duplicating modules that are imported more than once.

Feature modules

Group a feature’s controller + service + DTOs + entity behind its own module, then import it from AppModule — one folder per feature, which is exactly what austial generate module <name> / austial generate resource <name> scaffold automatically (see CLI):

src/modules/cats/ ├── cats_module.py ├── cats_controller.py ├── cats_service.py ├── entities/cats_entity.py └── dto/ ├── create_cats_dto.py └── update_cats_dto.py
@Module(imports=[CatsModule], controllers=[AppController], providers=[AppService]) class AppModule: pass

Global modules

from austial import Global, Module @Global() @Module(providers=[ConfigService], exports=[ConfigService]) class ConfigModule: pass

@Global() marks a module’s exports as available everywhere without every consumer needing to list it in their own imports (used internally by ConfigModule.for_root()).

A note on module visibility

Austial’s DI container is currently application-wide and flat: every module’s providers register into the same Container instance regardless of imports/exports. In practice this means anything registered anywhere in the graph is resolvable anywhere else — imports and exports are honored for scanning (so you must still import a module for its controllers/providers to be registered at all) but are not yet enforced as a visibility boundary. Write your imports/exports correctly anyway: it documents intent and means nothing changes for your code if/when strict visibility lands.

Dynamic modules

ConfigModule.for_root(...) and DatabaseModule.for_root_async(...) are dynamic modules — static methods that build and return module metadata at runtime instead of a fixed @Module(...) decorator. See Dynamic Modules for how to write your own.

Last updated on