or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-setup.mdcomponents.mddependency-injection.mderror-handling.mdindex.mdmodules-and-definitions.mdqualifiers-parameters.mdscoping.md

dependency-injection.mddocs/

0

# Core Dependency Injection

1

2

This document covers the core dependency injection capabilities provided by the `Koin` class and how to resolve dependencies throughout your application.

3

4

## Overview

5

6

Koin provides several ways to inject and resolve dependencies:

7

- **Direct resolution** using `get()` - Immediately resolve an instance

8

- **Lazy injection** using `inject()` - Defer resolution until first access

9

- **Nullable variants** - Handle optional dependencies gracefully

10

- **Collection resolution** - Get all instances of a type

11

- **Instance declaration** - Register instances at runtime

12

13

All injection methods work through the `Koin` context, which acts as the main dependency resolution hub.

14

15

## Koin Context

16

17

The `Koin` class is the central dependency injection context:

18

19

```kotlin { .api }

20

class Koin {

21

// Core resolution methods

22

inline fun <reified T : Any> get(

23

qualifier: Qualifier? = null,

24

noinline parameters: ParametersDefinition? = null

25

): T

26

27

inline fun <reified T : Any> inject(

28

qualifier: Qualifier? = null,

29

mode: LazyThreadSafetyMode = KoinPlatformTools.defaultLazyMode(),

30

noinline parameters: ParametersDefinition? = null

31

): Lazy<T>

32

33

// Nullable variants

34

inline fun <reified T : Any> getOrNull(/* ... */): T?

35

inline fun <reified T : Any> injectOrNull(/* ... */): Lazy<T?>

36

37

// Non-reified variants

38

fun <T> get(clazz: KClass<*>, qualifier: Qualifier?, parameters: ParametersDefinition?): T

39

fun <T> getOrNull(clazz: KClass<*>, qualifier: Qualifier?, parameters: ParametersDefinition?): T?

40

41

// Collection resolution

42

inline fun <reified T> getAll(): List<T>

43

44

// Runtime declaration

45

inline fun <reified T> declare(

46

instance: T,

47

qualifier: Qualifier? = null,

48

secondaryTypes: List<KClass<*>> = emptyList(),

49

allowOverride: Boolean = true

50

)

51

}

52

```

53

54

## Direct Resolution with get()

55

56

Use `get()` to immediately resolve and obtain an instance:

57

58

### Basic Usage

59

60

```kotlin

61

import org.koin.core.*

62

import org.koin.dsl.*

63

64

// Define dependencies

65

val appModule = module {

66

single<Repository> { DatabaseRepository() }

67

factory<UseCase> { GetDataUseCase(get()) }

68

}

69

70

val koinApp = koinApplication { modules(appModule) }

71

val koin = koinApp.koin

72

73

// Direct resolution

74

val repository: Repository = koin.get()

75

val useCase: UseCase = koin.get()

76

```

77

78

### With Qualifiers

79

80

```kotlin

81

import org.koin.core.qualifier.named

82

83

val networkModule = module {

84

single<ApiService>(named("v1")) { ApiServiceV1() }

85

single<ApiService>(named("v2")) { ApiServiceV2() }

86

}

87

88

val koin = koinApplication { modules(networkModule) }.koin

89

90

// Resolve with qualifier

91

val apiV1: ApiService = koin.get(named("v1"))

92

val apiV2: ApiService = koin.get(named("v2"))

93

```

94

95

### With Parameters

96

97

```kotlin

98

import org.koin.core.parameter.parametersOf

99

100

val configModule = module {

101

factory<DatabaseConfig> { params ->

102

val url: String = params.get()

103

val port: Int = params.get()

104

DatabaseConfig(url, port)

105

}

106

}

107

108

val koin = koinApplication { modules(configModule) }.koin

109

110

// Resolve with parameters

111

val config: DatabaseConfig = koin.get {

112

parametersOf("localhost", 5432)

113

}

114

```

115

116

### Non-Reified Resolution

117

118

For cases where you need to resolve using `KClass`:

119

120

```kotlin

121

import kotlin.reflect.KClass

122

123

val repository = koin.get<Repository>(

124

clazz = Repository::class,

125

qualifier = named("primary"),

126

parameters = { parametersOf("config") }

127

)

128

```

129

130

## Lazy Injection with inject()

131

132

Use `inject()` for lazy resolution - the instance is created only when first accessed:

133

134

### Basic Lazy Injection

135

136

```kotlin

137

val serviceModule = module {

138

single<HeavyService> { HeavyService() }

139

}

140

141

val koin = koinApplication { modules(serviceModule) }.koin

142

143

// Lazy injection - HeavyService not created yet

144

val service: Lazy<HeavyService> = koin.inject()

145

146

// HeavyService created here on first access

147

val actualService = service.value

148

```

149

150

### Thread Safety Modes

151

152

Control how lazy instances handle concurrent access:

153

154

```kotlin

155

import org.koin.mp.KoinPlatformTools

156

157

// Default platform-specific mode

158

val service1: Lazy<Service> = koin.inject()

159

160

// Synchronized access (thread-safe)

161

val service2: Lazy<Service> = koin.inject(mode = LazyThreadSafetyMode.SYNCHRONIZED)

162

163

// No synchronization (fastest, but not thread-safe)

164

val service3: Lazy<Service> = koin.inject(mode = LazyThreadSafetyMode.NONE)

165

166

// Publication safety (thread-safe initialization, but allows multiple writes)

167

val service4: Lazy<Service> = koin.inject(mode = LazyThreadSafetyMode.PUBLICATION)

168

```

169

170

### Lazy Injection with Parameters

171

172

```kotlin

173

val parameterizedService: Lazy<ConfigurableService> = koin.inject {

174

parametersOf("production", 30)

175

}

176

177

// Parameters evaluated when lazy value is accessed

178

val service = parameterizedService.value

179

```

180

181

## Nullable Resolution

182

183

Handle optional dependencies gracefully:

184

185

### Nullable Direct Resolution

186

187

```kotlin

188

val optionalModule = module {

189

single<RequiredService> { RequiredService() }

190

// OptionalService not defined

191

}

192

193

val koin = koinApplication { modules(optionalModule) }.koin

194

195

// Required service - will succeed

196

val required: RequiredService = koin.get()

197

198

// Optional service - returns null instead of throwing

199

val optional: OptionalService? = koin.getOrNull()

200

201

if (optional != null) {

202

// Use optional service

203

optional.doSomething()

204

}

205

```

206

207

### Nullable Lazy Injection

208

209

```kotlin

210

val optionalService: Lazy<OptionalService?> = koin.injectOrNull()

211

212

// Check if service is available when accessed

213

val service = optionalService.value

214

if (service != null) {

215

service.performAction()

216

}

217

```

218

219

### Nullable with Qualifiers and Parameters

220

221

```kotlin

222

val optionalConfig: DatabaseConfig? = koin.getOrNull(

223

qualifier = named("test"),

224

parameters = { parametersOf("test-db") }

225

)

226

```

227

228

## Collection Resolution

229

230

Get all registered instances of a specific type:

231

232

### Basic Collection Resolution

233

234

```kotlin

235

val pluginModule = module {

236

single<Plugin> { PluginA() }

237

single<Plugin> { PluginB() }

238

single<Plugin> { PluginC() }

239

}

240

241

val koin = koinApplication { modules(pluginModule) }.koin

242

243

// Get all Plugin instances

244

val allPlugins: List<Plugin> = koin.getAll()

245

246

allPlugins.forEach { plugin ->

247

plugin.initialize()

248

}

249

```

250

251

### With Different Qualifiers

252

253

```kotlin

254

val handlerModule = module {

255

single<EventHandler>(named("auth")) { AuthEventHandler() }

256

single<EventHandler>(named("payment")) { PaymentEventHandler() }

257

factory<EventHandler>(named("logging")) { LoggingEventHandler() }

258

}

259

260

val koin = koinApplication { modules(handlerModule) }.koin

261

262

// Gets all EventHandler instances regardless of qualifiers

263

val allHandlers: List<EventHandler> = koin.getAll()

264

```

265

266

## Runtime Instance Declaration

267

268

Register instances dynamically at runtime:

269

270

### Basic Declaration

271

272

```kotlin

273

val koin = koinApplication { modules(emptyModule) }.koin

274

275

// Declare an instance at runtime

276

val runtimeConfig = RuntimeConfig("dynamic-value")

277

koin.declare(runtimeConfig)

278

279

// Now it can be resolved

280

val config: RuntimeConfig = koin.get()

281

```

282

283

### Declaration with Qualifiers

284

285

```kotlin

286

// Declare with specific qualifier

287

koin.declare(

288

instance = DatabaseConnection("prod-db"),

289

qualifier = named("production")

290

)

291

292

// Resolve with qualifier

293

val prodDb: DatabaseConnection = koin.get(named("production"))

294

```

295

296

### Multiple Type Bindings

297

298

```kotlin

299

interface Repository

300

interface ReadOnlyRepository

301

class DatabaseRepository : Repository, ReadOnlyRepository

302

303

val dbRepo = DatabaseRepository()

304

305

// Bind to multiple types

306

koin.declare(

307

instance = dbRepo,

308

secondaryTypes = listOf(ReadOnlyRepository::class),

309

allowOverride = false

310

)

311

312

// Can resolve as either type

313

val repo: Repository = koin.get()

314

val readOnly: ReadOnlyRepository = koin.get()

315

```

316

317

### Override Control

318

319

```kotlin

320

// First declaration

321

koin.declare(UserService("v1"))

322

323

// Override existing - will succeed with allowOverride = true

324

koin.declare(

325

instance = UserService("v2"),

326

allowOverride = true

327

)

328

329

// This would fail with allowOverride = false

330

// koin.declare(UserService("v3"), allowOverride = false) // Exception!

331

```

332

333

## Global Context Access

334

335

For applications using a global Koin context:

336

337

### Starting Global Context

338

339

```kotlin { .api }

340

import org.koin.core.context.*

341

342

// Start global context

343

fun startKoin(koinApplication: KoinApplication): KoinApplication

344

fun startKoin(appDeclaration: KoinAppDeclaration): KoinApplication

345

346

// Stop global context

347

fun stopKoin(): Unit

348

349

// Module management in global context

350

fun loadKoinModules(module: Module): Unit

351

fun loadKoinModules(modules: List<Module>): Unit

352

fun unloadKoinModules(module: Module): Unit

353

fun unloadKoinModules(modules: List<Module>): Unit

354

```

355

356

### Using Global Context

357

358

```kotlin

359

import org.koin.core.context.*

360

import org.koin.dsl.*

361

362

// Start global context

363

startKoin {

364

modules(appModule)

365

}

366

367

// The global context is now available through KoinPlatformTools

368

// Components can access it without explicit Koin reference

369

```

370

371

## Scoped Resolution

372

373

Dependencies can also be resolved within specific scopes (covered in detail in [Scope Management](scoping.md)):

374

375

```kotlin

376

val scopedModule = module {

377

scope<UserSession> {

378

scoped<UserData> { UserData(get()) }

379

}

380

}

381

382

val koin = koinApplication { modules(scopedModule) }.koin

383

val userScope = koin.createScope<UserSession>("user-123")

384

385

// Resolve within scope

386

val userData: UserData = userScope.get()

387

```

388

389

## Best Practices

390

391

### 1. Prefer Lazy Injection for Expensive Resources

392

393

```kotlin

394

// Good - lazy initialization

395

val heavyService: Lazy<HeavyService> = koin.inject()

396

397

// Use only when needed

398

if (someCondition) {

399

heavyService.value.performOperation()

400

}

401

```

402

403

### 2. Use Nullable Variants for Optional Dependencies

404

405

```kotlin

406

class OptionalFeatureService(

407

private val required: RequiredService,

408

private val optional: OptionalService? = null

409

) {

410

fun performAction() {

411

required.execute()

412

optional?.enhanceExecution()

413

}

414

}

415

416

val service = OptionalFeatureService(

417

required = koin.get(),

418

optional = koin.getOrNull()

419

)

420

```

421

422

### 3. Handle Collections Appropriately

423

424

```kotlin

425

// Initialize all plugins

426

val plugins: List<Plugin> = koin.getAll()

427

plugins.forEach { it.initialize() }

428

429

// Process with handlers

430

val handlers: List<EventHandler> = koin.getAll()

431

val event = Event("user.login")

432

handlers.forEach { handler ->

433

handler.handle(event)

434

}

435

```

436

437

### 4. Runtime Declaration for Dynamic Configuration

438

439

```kotlin

440

class ConfigurableApplication {

441

fun configureEnvironment(environment: String, koin: Koin) {

442

when (environment) {

443

"development" -> {

444

koin.declare(DevConfig(), named("env"))

445

}

446

"production" -> {

447

koin.declare(ProdConfig(), named("env"))

448

}

449

}

450

}

451

}

452

```

453

454

This flexible resolution system enables clean dependency injection patterns while maintaining type safety and supporting various usage scenarios from simple direct resolution to complex lazy initialization strategies.