Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khode-io/nest-dart/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The ApplicationContainer class is the entry point for Nest Dart applications. It manages module registration, service resolution, and provides a unified interface for accessing services across your application. Key Features:
  • Module registration and initialization
  • Centralized service resolution
  • Automatic dependency ordering
  • Lifecycle management
  • Export control and encapsulation
  • Testing support with reset functionality

Class Definition

class ApplicationContainer

Constructor

ApplicationContainer([GetIt? getIt])
Creates a new application container.
getIt
GetIt
Optional GetIt instance. If not provided, uses GetIt.instance.
Example:
// Use default GetIt instance
final container = ApplicationContainer();

// Use custom GetIt instance (useful for testing)
final testContainer = ApplicationContainer(GetIt.asNewInstance());

Properties

isReady

bool get isReady
Check if the container is ready (all modules initialized). Returns: bool - true if all modules have been initialized, false otherwise. Example:
final container = ApplicationContainer();
await container.registerModule(AppModule());

if (container.isReady) {
  print('Container is ready!');
}

modules

List<Module> get modules
Get all registered modules as an unmodifiable list. Returns: List<Module> - Immutable list of registered modules. Example:
final container = ApplicationContainer();
await container.registerModule(UserModule());
await container.registerModule(AuthModule());

print('Registered modules: ${container.modules.length}');

context

ModuleContext get context
Get the module context (useful for testing and debugging). Returns: ModuleContext - The internal module context tracking imports/exports.
This property is primarily useful for testing and debugging module relationships.

getIt

GetIt get getIt
Get the underlying GetIt instance. Returns: GetIt - The wrapped GetIt dependency injection container.
Direct access to GetIt bypasses module restrictions. Use with caution and prefer the container’s get() method.

Methods

registerModule

Future<void> registerModule(Module module) async
Register a module with the container. This makes the module’s exported services available to the application and triggers initialization.
module
Module
required
The module to register with the container.
Returns: Future<void> Process:
  1. Registers the module and all its dependencies
  2. Makes exported services globally available
  3. Calls onModuleInit on the module and its dependencies
  4. Marks the container as ready
Example:
final container = ApplicationContainer();

// Register a single module
await container.registerModule(UserModule());

// Access exported services
final userService = container.get<UserService>();

registerModules

Future<void> registerModules(List<Module> modules) async
Register multiple modules at once.
modules
List<Module>
required
List of modules to register.
Returns: Future<void> Example:
final container = ApplicationContainer();

await container.registerModules([
  UserModule(),
  AuthModule(),
  DatabaseModule(),
]);

get

T get<T extends Object>({String? instanceName})
Get a service instance from the container. Services are only accessible if they are exported by registered modules.
T
Type
required
The type of service to retrieve.
instanceName
String
Optional named instance identifier.
Returns: T - The requested service instance. Throws: ServiceNotExportedException if the service is not accessible. Example:
// Get a service by type
final userService = container.get<UserService>();

// Get a named instance
final primaryDb = container.get<Database>(instanceName: 'primary');
final secondaryDb = container.get<Database>(instanceName: 'secondary');

getWithParams

T getWithParams<T extends Object>(dynamic param1, [dynamic param2])
Get a service instance with runtime parameters (for factories registered with parameters).
T
Type
required
The type of service to retrieve.
param1
dynamic
required
First parameter to pass to the factory.
param2
dynamic
Optional second parameter to pass to the factory.
Returns: T - The requested service instance. Throws: ServiceNotExportedException if the service is not accessible. Example:
// Register factory with params in module
locator.registerFactoryParam<UserLogger, String, LogLevel>(
  (userId, logLevel) => UserLogger(userId, logLevel),
);

// Get instance with params
final logger = container.getWithParams<UserLogger>('user123', LogLevel.info);

getAsync

Future<T> getAsync<T extends Object>({String? instanceName})
Get an asynchronously initialized service instance.
T
Type
required
The type of service to retrieve.
instanceName
String
Optional named instance identifier.
Returns: Future<T> - The requested service instance. Throws: ServiceNotExportedException if the service is not accessible. Example:
// Register async singleton in module
locator.registerSingletonAsync<Database>(
  () async {
    final db = Database();
    await db.connect();
    return db;
  }
);

// Get async service
final database = await container.getAsync<Database>();

isRegistered

bool isRegistered<T extends Object>({String? instanceName})
Check if a service is registered and accessible from the application container.
T
Type
required
The type of service to check.
instanceName
String
Optional named instance identifier.
Returns: bool - true if the service is registered and accessible. Example:
if (container.isRegistered<UserService>()) {
  final service = container.get<UserService>();
}

isRegisteredInContainer

bool isRegisteredInContainer<T extends Object>({String? instanceName})
Check if a service is registered in the underlying container, ignoring export restrictions.
T
Type
required
The type of service to check.
instanceName
String
Optional named instance identifier.
Returns: bool - true if the service is registered (even if not accessible).
This method checks for registration regardless of export status. Use isRegistered() to check if a service is accessible.

getAvailableServices

Set<Type> getAvailableServices()
Get all services available to the root container. Returns: Set<Type> - Set of all accessible service types. Example:
final services = container.getAvailableServices();
print('Available services: ${services.map((t) => t.toString()).join(", ")}');

waitUntilReady

Future<void> waitUntilReady({Duration? timeout})
Wait for the container to be ready (all modules initialized).
timeout
Duration
Optional timeout duration. Throws TimeoutException if exceeded.
Returns: Future<void> Throws: TimeoutException if initialization exceeds the timeout. Example:
final container = ApplicationContainer();

// Start registration in background
container.registerModule(AppModule()).ignore();

// Wait for completion with timeout
await container.waitUntilReady(
  timeout: Duration(seconds: 30),
);

print('Container ready!');

allReady

Future<void> allReady({
  Duration? timeout,
  bool ignorePendingAsyncCreation = false,
})
Wait for all services to be ready (delegates to GetIt’s allReady method).
timeout
Duration
Optional timeout duration.
ignorePendingAsyncCreation
bool
default:"false"
Whether to ignore pending async service creation.
Returns: Future<void> Example:
await container.registerModule(AppModule());
await container.allReady(timeout: Duration(seconds: 10));
print('All services ready!');

reset

Future<void> reset() async
Reset the container, destroying all modules and clearing all registrations. Useful for testing. Returns: Future<void> Process:
  1. Calls onModuleDestroy on all modules in reverse initialization order
  2. Resets the underlying GetIt container
  3. Clears all module registrations
  4. Clears module context
  5. Marks container as not ready
Example:
test('user service test', () async {
  final container = ApplicationContainer();
  await container.registerModule(UserModule());
  
  // Run tests...
  
  // Clean up
  await container.reset();
});
Resetting the container will dispose all singleton instances. Make sure to properly handle cleanup in your module’s onModuleDestroy method.

Complete Example

import 'package:nest_core/core.dart';

// Define modules
class DatabaseModule extends Module {
  @override
  Future<void> providers(Locator locator) async {
    locator.registerSingleton<Database>(Database());
  }
  
  @override
  List<Type> get exports => [Database];
}

class UserModule extends Module {
  @override
  List<Module> get imports => [DatabaseModule()];
  
  @override
  Future<void> providers(Locator locator) async {
    locator.registerLazySingleton<UserRepository>(
      () => UserRepository(locator.get<Database>()),
    );
    locator.registerLazySingleton<UserService>(
      () => UserService(locator.get<UserRepository>()),
    );
  }
  
  @override
  List<Type> get exports => [UserService];
}

class AppModule extends Module {
  @override
  List<Module> get imports => [UserModule()];
}

// Application entry point
void main() async {
  // Create container
  final container = ApplicationContainer();
  
  // Register root module (imports UserModule -> DatabaseModule)
  await container.registerModule(AppModule());
  
  // Wait for all services to be ready
  await container.allReady();
  
  print('Container initialized in ${container.isReady}');
  print('Available services: ${container.getAvailableServices()}');
  
  // Access services
  final userService = container.get<UserService>();
  final users = await userService.getAllUsers();
  
  print('Loaded ${users.length} users');
}

Testing Example

import 'package:test/test.dart';
import 'package:nest_core/core.dart';

void main() {
  late ApplicationContainer container;
  
  setUp(() async {
    // Create fresh container for each test
    container = ApplicationContainer(GetIt.asNewInstance());
    await container.registerModule(AppModule());
  });
  
  tearDown(() async {
    // Clean up after each test
    await container.reset();
  });
  
  test('should access user service', () async {
    final userService = container.get<UserService>();
    expect(userService, isNotNull);
  });
  
  test('should throw when accessing non-exported service', () {
    expect(
      () => container.get<UserRepository>(),
      throwsA(isA<ServiceNotExportedException>()),
    );
  });
}

Best Practices

  1. Single container instance: Create one container per application
  2. Register at startup: Register all modules during application initialization
  3. Wait for ready: Use waitUntilReady() before accessing services
  4. Use isolated containers for tests: Create new GetIt instances for each test
  5. Reset in tearDown: Always reset the container in test tearDown
  6. Prefer get<T>(): Use the container’s get() method instead of accessing GetIt directly

Build docs developers (and LLMs) love