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.