Lightweight dependency injection for Kotlin. Auto-resolution, scoped lifecycles, thread safety — no code generation, no annotations, zero configuration.
implementation("com.cristianllanos:container:0.4.0")Concrete classes resolve automatically via constructor reflection. No registration, no annotations — just works.
Factory, singleton, and scoped bindings with nested scopes, dispose hooks, and AutoCloseable support.
Singletons created exactly once under contention. Per-thread circular dependency detection with no false positives.
Group registrations into providers with auto-resolved parameters. Clean, modular setup.
Invoke any function with dependencies resolved from the container. Works with free functions and instance methods.
Registrar, Resolver, Caller, Container, Scope — give each part of your code only the access it needs.
Concrete classes resolve automatically — no registration needed.
class Logger
class UserRepository(val logger: Logger)
class UserService(val repo: UserRepository)
val container = Container()
val service = container.resolve<UserService>()
// resolves Logger → UserRepository → UserService automaticallyUse factory, singleton, or scoped when you need explicit control.
val container = Container {
// New instance every time
factory<PaymentGateway> { StripeGateway() }
// One instance forever
singleton<NotificationService> { SlackNotificationService() }
// One instance per scope
scoped<DbConnection> { DbConnection(resolve<Config>()) }
}
// Auto-resolved registration (no lambda needed)
container.singleton<TenantService>()
container.factory<TempProcessor>()One instance per scope — shared within a context, isolated between contexts.
container.scoped<DbConnection> { DbConnection() }
.onClose { it.disconnect() }
container.scope { scope ->
val db = scope.resolve<DbConnection>() // created once
scope.resolve<DbConnection>() // same instance
} // scope closes → db.disconnect() called
// Nested scopes cascade close (deepest first)
// AutoCloseable instances close automaticallyGroup related registrations. Parameters are auto-resolved from the container.
class AuthServiceProvider {
fun register(container: Container) {
container.singleton<TokenStore> { RedisTokenStore() }
container.singleton<AuthGuard> { AuthGuard(resolve<TokenStore>()) }
}
}
class EventServiceProvider {
fun register(subscriber: Subscriber) { // auto-resolved!
subscriber.subscribe<OrderPlaced>(
InventoryListener::class,
NotificationListener::class,
)
}
}
val container = Container()
container.register(AuthServiceProvider(), EventServiceProvider())Install, create a container, resolve your first dependency tree.
Factory, singleton, and scoped — control how instances are created and shared.
Lifecycle management, dispose hooks, nested scopes, and contextual environments.
Group registrations into reusable, modular units with auto-resolved parameters.
Thread safety, callable injection, custom resolvers, and interface segregation.
Complete public API: interfaces, extension functions, types, and exceptions.
Release history and notable changes.
Add the dependency, create a container, and resolve. That's it.