Modules in Sword
In Sword, a module groups related pieces of the same application capability, such as controllers, components, and providers.
What problem do they solve?
As an application grows, registering everything directly in main.rs becomes unmaintainable. Modules allow you to:
- Group related functionality.
- Encapsulate dependency registration.
- Separate concerns by domain.
- Maintain a stable architecture as the app scales.
The Module Trait
The base contract is:
pub trait Module {
fn register_controllers(controllers: &ControllerRegistry) {}
fn register_components(components: &ComponentRegistry) {}
async fn register_providers(config: &Config, providers: &ProviderRegistry) {}
}All methods have an empty default implementation.
What each method registers
register_controllers(...)
Registers external entry points: HTTP, Socket.IO, and other controller types supported by the framework.
fn register_controllers(controllers: &ControllerRegistry) {
controllers.register::<UsersController>();
}register_components(...)
Registers #[injectable] structs that should be constructed from the dependency container.
fn register_components(components: &ComponentRegistry) {
components.register::<UserRepository>();
components.register::<UsersService>();
}register_providers(...)
Registers #[injectable(provider)] structs, typically external connections or clients: databases, caches, or remote services.
This method is async.
async fn register_providers(config: &Config, providers: &ProviderRegistry) {
let db_config = config.expect::<DatabaseConfig>();
providers.register(
Database::new(db_config)
.await
.expect("Failed to create Database provider"),
);
}Module Example
use sword::prelude::*;
pub struct UsersModule;
impl Module for UsersModule {
fn register_components(components: &ComponentRegistry) {
components.register::<UserRepository>();
components.register::<UsersService>();
}
fn register_controllers(controllers: &ControllerRegistry) {
controllers.register::<UsersController>();
}
}Application Registration
Modules are registered using with_module::<M>() in the ApplicationBuilder.
#[sword::main]
async fn main() {
let app = Application::builder()
.with_module::<SharedModule>()
.with_module::<UsersModule>()
.build();
app.run().await;
}with_module Behavior
Each call to with_module::<M>() executes the module registration in this order:
register_providers(...)register_components(...)register_controllers(...)
This order describes the module's internal registration, not the final dependency resolution.
The actual construction of components and container resolution happen later, during build(), when Sword executes the global container construction process with all registered modules.
Separation of Concerns
Exposes an external interface.
Examples: HTTP endpoint, Socket.IO namespace.Internal logic auto-constructed by DI.
Examples: domain service, repository, hasher.External resource or async initialization.
Examples: database, Redis client, external SDK.Standard Structure
A common structure is:
users/
controller.rs
service.rs
repository.rs
mod.rsAnd in mod.rs:
pub struct UsersModule;
impl Module for UsersModule {
// register users domain
}Partitioning Criteria
- When a domain area has its own controllers and dependencies.
- When it's beneficial to isolate registration and responsibilities.
- When
main.rsstarts accumulating wiring for multiple capabilities.

