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

scoping.mddocs/

0

# Scope Management

1

2

This document covers Koin's scoping system, which provides lifecycle management for dependencies by grouping related instances that should be created and destroyed together.

3

4

## Overview

5

6

Scopes in Koin enable you to:

7

- **Control instance lifecycles** - Create and destroy groups of related instances

8

- **Isolate dependencies** - Keep certain instances separate from global singletons

9

- **Manage resources** - Ensure proper cleanup when scope is closed

10

- **Link scopes** - Create hierarchical relationships between scopes

11

12

A scope represents a bounded context where instances live and die together, making it perfect for features like user sessions, request handling, or component lifecycles.

13

14

## Scope Class

15

16

The `Scope` class provides the container for scoped instances and resolution methods:

17

18

```kotlin { .api }

19

class Scope(

20

val scopeQualifier: Qualifier,

21

val id: ScopeID,

22

val isRoot: Boolean = false,

23

val scopeArchetype: TypeQualifier? = null,

24

@PublishedApi

25

internal val _koin: Koin

26

) : Lockable() {

27

val closed: Boolean

28

29

// Resolution methods

30

inline fun <reified T : Any> inject(

31

qualifier: Qualifier? = null,

32

mode: LazyThreadSafetyMode = LazyThreadSafetyMode.SYNCHRONIZED,

33

noinline parameters: ParametersDefinition? = null

34

): Lazy<T>

35

36

inline fun <reified T : Any> get(

37

qualifier: Qualifier? = null,

38

noinline parameters: ParametersDefinition? = null

39

): T

40

41

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

42

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

43

44

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

45

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

46

47

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

48

49

// Scope operations

50

fun linkTo(vararg scopes: Scope)

51

fun unlink(vararg scopes: Scope)

52

fun close()

53

54

// Instance declaration

55

inline fun <reified T> declare(

56

instance: T,

57

qualifier: Qualifier? = null,

58

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

59

allowOverride: Boolean = true,

60

holdInstance: Boolean = false

61

)

62

63

// Scope access

64

fun getKoin(): Koin

65

fun getScope(scopeID: ScopeID): Scope

66

67

// Callbacks

68

fun registerCallback(callback: ScopeCallback)

69

70

// Properties (inherited from Koin)

71

fun <T : Any> getProperty(key: String, defaultValue: T): T

72

fun <T : Any> getPropertyOrNull(key: String): T?

73

fun <T : Any> getProperty(key: String): T

74

}

75

76

typealias ScopeID = String

77

```

78

79

## Creating Scopes

80

81

### Basic Scope Creation

82

83

```kotlin

84

import org.koin.core.qualifier.named

85

86

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

87

88

// Create scope with qualifier and ID

89

val userScope = koin.createScope("user-123", named("user"))

90

91

// Create scope with type-based qualifier

92

val sessionScope = koin.createScope<UserSession>("session-456")

93

94

// Create scope with auto-generated ID

95

val tempScope = koin.createScope<TempData>()

96

```

97

98

### Scope Creation Methods

99

100

```kotlin { .api }

101

// In Koin class

102

fun createScope(scopeId: ScopeID, qualifier: Qualifier, source: Any? = null, scopeArchetype: TypeQualifier? = null): Scope

103

104

inline fun <reified T : Any> createScope(scopeId: ScopeID, source: Any? = null, scopeArchetype: TypeQualifier? = null): Scope

105

106

inline fun <reified T : Any> createScope(scopeId: ScopeID = KoinPlatformTools.generateId()): Scope

107

108

fun <T : KoinScopeComponent> createScope(t: T): Scope

109

110

// Get or create patterns

111

fun getOrCreateScope(scopeId: ScopeID, qualifier: Qualifier, source: Any? = null): Scope

112

inline fun <reified T : Any> getOrCreateScope(scopeId: ScopeID): Scope

113

```

114

115

### Practical Scope Creation Examples

116

117

```kotlin

118

class UserSession(val userId: String)

119

class ShoppingCart(val sessionId: String)

120

121

// User session scope

122

val userSession = UserSession("user-123")

123

val sessionScope = koin.createScope<UserSession>("session-${userSession.userId}")

124

125

// Shopping cart scope

126

val cartScope = koin.createScope("cart-abc", named("shopping"))

127

128

// Get or create - won't create duplicate if exists

129

val existingScope = koin.getOrCreateScope<UserSession>("session-user-123")

130

```

131

132

## Defining Scoped Dependencies

133

134

### Scope DSL

135

136

```kotlin { .api }

137

class ScopeDSL(val scopeQualifier: Qualifier, val module: Module) {

138

inline fun <reified T> scoped(

139

qualifier: Qualifier? = null,

140

noinline definition: Definition<T>

141

): KoinDefinition<T>

142

143

inline fun <reified T> factory(

144

qualifier: Qualifier? = null,

145

noinline definition: Definition<T>

146

): KoinDefinition<T>

147

}

148

```

149

150

### Basic Scoped Definitions

151

152

```kotlin

153

import org.koin.dsl.*

154

import org.koin.core.qualifier.named

155

156

val userModule = module {

157

// Define a scope for user sessions

158

scope(named("user")) {

159

scoped<UserPreferences> { UserPreferences() }

160

scoped<UserCache> { UserCache() }

161

factory<UserActivity> { UserActivity() } // New instance each time

162

}

163

}

164

```

165

166

### Type-Based Scoped Definitions

167

168

```kotlin

169

class UserSession

170

class PaymentFlow

171

172

val scopedModule = module {

173

// Type-based scope definition

174

scope<UserSession> {

175

scoped<SessionData> { SessionData() }

176

scoped<AuthToken> { AuthToken() }

177

}

178

179

scope<PaymentFlow> {

180

scoped<PaymentData> { PaymentData() }

181

scoped<TransactionLog> { TransactionLog() }

182

}

183

}

184

```

185

186

### Scoped Dependencies with Injection

187

188

```kotlin

189

val advancedScopeModule = module {

190

// Global singletons

191

single<Database> { Database() }

192

single<Logger> { Logger() }

193

194

scope<UserSession> {

195

// Scoped instances can inject global singletons

196

scoped<UserRepository> { UserRepository(get()) } // Injects Database

197

198

// Scoped instances can inject other scoped instances

199

scoped<UserService> {

200

UserService(get<UserRepository>(), get<Logger>())

201

}

202

203

// Factory within scope

204

factory<UserQuery> { params ->

205

val queryType: String = params.get()

206

UserQuery(queryType, get<UserRepository>())

207

}

208

}

209

}

210

```

211

212

## Working with Scopes

213

214

### Resolving Scoped Dependencies

215

216

```kotlin

217

// Create scope instance

218

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

219

220

// Resolve scoped dependencies

221

val userService: UserService = userScope.get()

222

val userRepo: UserRepository = userScope.get()

223

224

// Lazy resolution

225

val userCache: Lazy<UserCache> = userScope.inject()

226

227

// With parameters

228

val userQuery: UserQuery = userScope.get { parametersOf("findByEmail") }

229

230

// Nullable resolution

231

val optionalService: OptionalService? = userScope.getOrNull()

232

```

233

234

### Scope Instance Lifecycle

235

236

```kotlin

237

// Create and use scope

238

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

239

240

// All scoped instances are created as needed

241

val service1 = scope.get<UserService>() // Creates UserService + dependencies

242

val service2 = scope.get<UserService>() // Returns same UserService instance

243

244

// Close scope - destroys all scoped instances

245

scope.close()

246

247

// Attempting to use closed scope throws exception

248

// val service3 = scope.get<UserService>() // ClosedScopeException!

249

```

250

251

### Scope Linking

252

253

Create hierarchical relationships between scopes:

254

255

```kotlin

256

// Parent scope

257

val applicationScope = koin.createScope<Application>("app")

258

259

// Child scope linked to parent

260

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

261

userScope.linkTo(applicationScope)

262

263

// Child can resolve from parent scope

264

val appConfig: AppConfig = userScope.get() // Resolves from applicationScope

265

266

// Multiple links

267

val requestScope = koin.createScope<RequestContext>("request-456")

268

requestScope.linkTo(userScope, applicationScope) // Links to both

269

270

// Unlinking

271

requestScope.unlink(applicationScope)

272

```

273

274

### Scope Callbacks

275

276

Register callbacks for scope lifecycle events:

277

278

```kotlin

279

import org.koin.core.scope.ScopeCallback

280

281

class UserSessionCallback : ScopeCallback {

282

override fun onScopeClose(scope: Scope) {

283

println("User session ${scope.id} is closing")

284

// Cleanup user-specific resources

285

}

286

}

287

288

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

289

userScope.registerCallback(UserSessionCallback())

290

291

// When scope closes, callback is invoked

292

userScope.close() // Prints: "User session user-123 is closing"

293

```

294

295

## Runtime Scope Declaration

296

297

Declare instances directly in scopes at runtime:

298

299

### Basic Declaration

300

301

```kotlin

302

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

303

304

// Declare instance in scope

305

val sessionData = SessionData("user-123", "premium")

306

userScope.declare(sessionData)

307

308

// Now available for resolution

309

val data: SessionData = userScope.get()

310

```

311

312

### Declaration with Options

313

314

```kotlin

315

// Declare with qualifier

316

userScope.declare(

317

instance = UserPreferences("dark-mode"),

318

qualifier = named("ui")

319

)

320

321

// Declare with multiple type bindings

322

interface Cache

323

class UserCache : Cache

324

325

userScope.declare(

326

instance = UserCache(),

327

secondaryTypes = listOf(Cache::class)

328

)

329

330

// Can resolve as either type

331

val cache: Cache = userScope.get()

332

val userCache: UserCache = userScope.get()

333

```

334

335

### Hold Instance Control

336

337

```kotlin

338

// Instance held in scope (default)

339

userScope.declare(

340

instance = PersistentData(),

341

holdInstance = true // Available in this and future scope instances

342

)

343

344

// Instance not held in scope

345

userScope.declare(

346

instance = TemporaryData(),

347

holdInstance = false // Only available in current scope instance

348

)

349

```

350

351

## Advanced Scope Patterns

352

353

### User Session Management

354

355

```kotlin

356

class UserSessionManager(private val koin: Koin) {

357

private val userScopes = mutableMapOf<String, Scope>()

358

359

fun startUserSession(userId: String): Scope {

360

val scope = koin.createScope<UserSession>("user-$userId")

361

362

// Initialize session-specific data

363

scope.declare(UserSessionData(userId))

364

scope.declare(UserPreferences.load(userId))

365

366

userScopes[userId] = scope

367

return scope

368

}

369

370

fun endUserSession(userId: String) {

371

userScopes[userId]?.close()

372

userScopes.remove(userId)

373

}

374

375

fun getUserScope(userId: String): Scope? {

376

return userScopes[userId]

377

}

378

}

379

```

380

381

### Request-Scoped Processing

382

383

```kotlin

384

class RequestProcessor(private val koin: Koin) {

385

fun processRequest(requestId: String): Response {

386

val requestScope = koin.createScope<RequestContext>(requestId)

387

388

try {

389

// Declare request-specific data

390

requestScope.declare(RequestData(requestId))

391

392

// Process with scoped dependencies

393

val processor: RequestHandler = requestScope.get()

394

return processor.handle()

395

396

} finally {

397

// Always cleanup

398

requestScope.close()

399

}

400

}

401

}

402

```

403

404

### Hierarchical Scope Architecture

405

406

```kotlin

407

class ApplicationArchitecture {

408

fun setupScopes(): Triple<Scope, Scope, Scope> {

409

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

410

411

// Application level - global for app lifetime

412

val appScope = koin.createScope<Application>("app")

413

414

// Feature level - for specific feature lifetime

415

val featureScope = koin.createScope<FeatureContext>("feature-user")

416

featureScope.linkTo(appScope)

417

418

// Request level - for individual request lifetime

419

val requestScope = koin.createScope<RequestContext>("request-123")

420

requestScope.linkTo(featureScope, appScope)

421

422

return Triple(appScope, featureScope, requestScope)

423

}

424

}

425

```

426

427

### Scope-Based Component Isolation

428

429

```kotlin

430

// Different scope contexts for different features

431

val eCommerceModule = module {

432

scope<ShoppingCart> {

433

scoped<CartService> { CartService() }

434

scoped<PriceCalculator> { PriceCalculator() }

435

}

436

437

scope<Checkout> {

438

scoped<PaymentProcessor> { PaymentProcessor() }

439

scoped<OrderService> { OrderService() }

440

factory<Receipt> { Receipt() }

441

}

442

}

443

444

// Usage

445

val cartScope = koin.createScope<ShoppingCart>("cart-user123")

446

val checkoutScope = koin.createScope<Checkout>("checkout-order456")

447

448

// Services are isolated per scope

449

val cartService1 = cartScope.get<CartService>() // ShoppingCart scope instance

450

val paymentProcessor = checkoutScope.get<PaymentProcessor>() // Checkout scope instance

451

```

452

453

## Error Handling

454

455

Scope-related exceptions:

456

457

```kotlin

458

// ClosedScopeException - using closed scope

459

val scope = koin.createScope<UserSession>("test")

460

scope.close()

461

// val service = scope.get<Service>() // Throws ClosedScopeException

462

463

// ScopeNotCreatedException - accessing non-existent scope

464

// val nonExistent = koin.getScope("does-not-exist") // Throws ScopeNotCreatedException

465

466

// ScopeAlreadyCreatedException - creating duplicate scope

467

val scope1 = koin.createScope<UserSession>("duplicate")

468

// val scope2 = koin.createScope<UserSession>("duplicate") // May throw ScopeAlreadyCreatedException

469

```

470

471

## Best Practices

472

473

### 1. Use Clear Scope Boundaries

474

475

```kotlin

476

// Good - clear lifecycle boundaries

477

class UserSessionScope {

478

companion object {

479

fun create(koin: Koin, userId: String): Scope {

480

return koin.createScope<UserSession>("user-$userId")

481

}

482

}

483

}

484

```

485

486

### 2. Always Close Scopes

487

488

```kotlin

489

// Use try-finally or use pattern

490

fun processUserRequest(userId: String) {

491

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

492

try {

493

val service: UserService = userScope.get()

494

service.processRequest()

495

} finally {

496

userScope.close() // Always cleanup

497

}

498

}

499

```

500

501

### 3. Link Scopes Appropriately

502

503

```kotlin

504

// Child scopes should link to parents for dependency resolution

505

val appScope = koin.createScope<Application>("app")

506

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

507

userScope.linkTo(appScope) // User scope can access app-level dependencies

508

```

509

510

### 4. Use Callbacks for Resource Cleanup

511

512

```kotlin

513

class ResourceCleanupCallback : ScopeCallback {

514

override fun onScopeClose(scope: Scope) {

515

// Cleanup any resources that need explicit cleanup

516

scope.getOrNull<FileResource>()?.close()

517

scope.getOrNull<NetworkConnection>()?.disconnect()

518

}

519

}

520

```

521

522

Scopes provide powerful lifecycle management capabilities that enable clean resource management and component isolation in complex applications.