# Koin Documentation (full text) > Every page of the Koin documentation, in sidebar order. Index: https://insert-koin.io/llms.txt # Welcome Source: https://insert-koin.io/docs/intro Koin is a dependency injection framework for Kotlin. You declare how your classes are built in modules, Koin creates and wires the instances at runtime, and the optional Koin Compiler Plugin checks the whole graph when you build. It runs on Android, Compose, Kotlin Multiplatform, Ktor and any Kotlin/JVM application. This page is a map of the documentation. Each section below says which question it answers and where to start. ```kotlin class UserRepository(private val api: ApiService) val appModule = module { single() single() } fun main() { startKoin { modules(appModule) } } ``` ## I want to... - Understand dependency injection first: [What is Dependency Injection?](/docs/intro/what-is-dependency-injection) - Understand how Koin works in five minutes: [Core Concepts](/docs/intro/core-concepts) - Pick between DSL and annotations: [Choosing your style](/docs/intro/choosing-your-style) - Add Koin to my Gradle build: [Gradle Setup](/docs/setup/gradle) - Inject a ViewModel in a Composable: [ViewModel in Compose](/docs/reference/koin-compose/compose-viewmodel) - Inject in an Activity, Fragment or Service: [Android Entry Points](/docs/reference/koin-android/entry-points) - Wire Retrofit, Room or OkHttp: [Android Library Integration](/docs/reference/koin-android/binding-patterns) - Share modules between Android and iOS: [KMP Sharing Patterns](/docs/reference/koin-core/kmp-shared-modules) - Pass a runtime value such as an ID to a definition: [Injected Parameters](/docs/reference/koin-core/injection-parameters) - Test my Koin configuration: [Verifying your Koin configuration](/docs/reference/koin-test/verify) and [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety) - Fix a "No definition found" error: [Troubleshooting](/docs/reference/koin-core/troubleshooting) - Migrate from Hilt: [Migrating from Hilt](/docs/reference/koin-android/hilt-migration) - Move my annotations from KSP to the Compiler Plugin: [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin) - See how Koin behaves in production: [Production Monitoring](/docs/tooling/production-monitoring) ## Where to go ### Get Started What is Koin, how does it work, which style should I use? - [What is Koin?](/docs/intro/what-is-koin): what Koin is and how it works, runtime and compile time. - [Core Concepts](/docs/intro/core-concepts): definitions, modules, the container, injection, scopes. - [Choosing your style](/docs/intro/choosing-your-style): annotations or the DSL (Compiler Plugin, Constructor or Classic DSL). - [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin): what the plugin does at build time. ### Setup What do I add to my build? - [Setup](/docs/setup): what to install for each platform. - [Gradle Setup](/docs/setup/gradle): the BOM and every Koin artifact. - [Compiler Plugin Setup](/docs/setup/compiler-plugin): install and configure the Gradle plugin. ### Tutorials How do I build a first app with Koin, step by step? - [Kotlin](/docs/quickstart/kotlin): a plain Kotlin application. - [Android - ViewModel](/docs/quickstart/android-viewmodel) and [Android - Jetpack Compose](/docs/quickstart/android-compose). - [Compose Multiplatform](/docs/quickstart/cmp): shared UI on Android and iOS. - [Ktor](/docs/quickstart/ktor): a server application. ### Core How do I declare, organize and retrieve dependencies on any platform? - [Starting Koin](/docs/reference/koin-core/starting-koin): `startKoin`, logging, properties. - [Modules](/docs/reference/koin-core/modules) and [Definitions](/docs/reference/koin-core/definitions): declare what Koin builds. - [Scopes](/docs/reference/koin-core/scopes): instances tied to a lifecycle. - [Troubleshooting](/docs/reference/koin-core/troubleshooting): errors and how to read them. ### Platforms How do I use Koin with a specific platform or framework? - Android: [Start Koin on Android](/docs/reference/koin-android/start), [Android ViewModel](/docs/reference/koin-android/viewmodel), [Multi-Module Android Apps](/docs/reference/koin-android/multi-module). - Compose: [Koin for Compose](/docs/reference/koin-compose/compose), [ViewModel in Compose](/docs/reference/koin-compose/compose-viewmodel), [Navigation 3](/docs/reference/koin-compose/navigation3). - Kotlin Multiplatform: [KMP Setup](/docs/reference/koin-core/kmp-setup), [Sharing Patterns](/docs/reference/koin-core/kmp-shared-modules). - Ktor: [Koin for Ktor](/docs/reference/koin-ktor/ktor), [Request Scopes](/docs/reference/koin-ktor/ktor-scopes). ### Testing How do I test code that uses Koin, and test the configuration itself? - [Injecting in Tests](/docs/reference/koin-test/testing): `KoinTest`, replacing definitions with fakes. - [Verifying your Koin configuration](/docs/reference/koin-test/verify): check modules in a unit test. - [Android Instrumented Testing](/docs/reference/koin-android/instrumented-testing) and [Testing Composables](/docs/reference/koin-compose/compose-testing). ### Production & Tooling Which tools help me write, inspect and run Koin apps? - [Tooling](/docs/tooling): overview of the tools around Koin. - [IDE Plugin](/docs/tooling/ide-plugin): navigation and checks in Android Studio and IntelliJ IDEA. - [Monitor](/docs/tooling/monitor) and [Production Monitoring](/docs/tooling/production-monitoring): see what Koin does at runtime. ### Migration I use another framework or an older Koin setup. How do I move? - [Koin vs Hilt](/docs/intro/koin-vs-hilt): how the two compare. - [Migrating from Hilt](/docs/reference/koin-android/hilt-migration): step-by-step guide. - [JSR-330 Compatibility](/docs/reference/koin-android/jsr330): keep `@Inject` and `@Singleton` from `javax.inject`. - [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin): move annotations to the Compiler Plugin. ### Reference What are all the keywords, annotations and options? - [DSL Reference](/docs/reference/koin-core/dsl): every DSL keyword. - [Annotations Reference](/docs/reference/koin-annotations/annotations-inventory): every annotation and its parameters. - [Compiler Plugin Options](/docs/reference/koin-annotations/options): every Gradle option of the plugin. ### Support Which version should I use, what changed, where do I get help? - [Releases](/docs/support/releases): versions, changes and upgrade notes. - [API Stability](/docs/support/api-stability): what stable, experimental and internal mean. - [Support](/docs/support): roadmap, community and support options. ## Related - [What is Koin?](/docs/intro/what-is-koin): the next page to read if you are new to Koin. - [Core Concepts](/docs/intro/core-concepts): the mental model behind every other page. - [Setup](/docs/setup): install Koin for your platform. --- # What is Dependency Injection? Source: https://insert-koin.io/docs/intro/what-is-dependency-injection Dependency injection (DI) is a design pattern where an object receives the objects it needs from outside instead of creating them itself. This page explains the pattern without assuming any framework, then shows where a DI container such as Koin fits. If you already know DI, go to [Core Concepts](/docs/intro/core-concepts). ## What is a dependency? A dependency is an object that another object needs to do its work. A `Car` needs an `Engine` to drive. ### Without dependency injection ```kotlin class Engine { fun start() { println("Engine starting...") } } class Car { private val engine = Engine() // Car creates its own engine fun drive() { engine.start() println("Car is driving") } } ``` This works, but it has costs: - **Tight coupling**: `Car` is tied to one `Engine` implementation. - **Hard to test**: you can't test `Car` with a fake engine. - **Hard to change**: switching to an electric engine means editing `Car`. - **Lifecycle in the wrong place**: `Car` decides when an `Engine` is created and how many exist. ### With dependency injection ```kotlin class Car(private val engine: Engine) { fun drive() { engine.start() println("Car is driving") } } val gasolineCar = Car(GasEngine()) val electricCar = Car(ElectricEngine()) ``` `Car` no longer knows how an `Engine` is built. You can pass any implementation, including a fake in tests, and the constructor shows exactly what `Car` needs. ## Ways to provide dependencies ### Constructor injection Dependencies are constructor parameters: ```kotlin class UserRepository( private val database: Database, private val apiClient: ApiClient, ) { fun getUser(id: String): User = database.query(id) ?: apiClient.fetchUser(id) } ``` Dependencies are explicit, required, and can be immutable (`val`). The class can be created and tested without any framework. This is the approach to use by default. ### Field injection Dependencies are assigned to properties after the object is created. This is needed when a framework creates the object and you don't control its constructor, as with an Android `Activity`: ```kotlin class UserActivity : AppCompatActivity() { private val viewModel: UserViewModel by viewModel() // filled by Koin on first access } ``` Use it only at these framework entry points. Below them, use constructor injection. ### Method injection A dependency is passed to the method that needs it: ```kotlin class ReportGenerator { fun generateReport(data: DataSource) { ... } } ``` This fits a dependency that changes on every call, or one that only one method uses. ## Manual and automated dependency injection ### Wiring by hand You can apply DI without any library, by building the object graph yourself: ```kotlin class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val database = Database() val apiClient = ApiClient() val userRepository = UserRepository(database, apiClient) val authRepository = AuthRepository(database, apiClient) val userService = UserService(userRepository, authRepository) val viewModel = UserViewModel(userService) } } ``` As the app grows, this code is repeated in many places, must be updated whenever a constructor changes, and gives no control over how long each object lives. ### A container written by hand A common next step is a container object that centralizes creation: ```kotlin object AppContainer { private val database by lazy { Database() } private val apiClient by lazy { ApiClient() } val userRepository by lazy { UserRepository(database, apiClient) } val authRepository by lazy { AuthRepository(database, apiClient) } fun createUserViewModel() = UserViewModel( UserService(userRepository, authRepository) ) } class MainActivity : AppCompatActivity() { private val viewModel = AppContainer.createUserViewModel() } ``` This removes the repetition, but you still write and maintain every constructor call, and lifecycles beyond "one instance" or "a new instance" (an instance per screen, per session) need more hand-written code. ### A DI container A DI library automates the container. You declare which classes exist and how long they live, and the library builds the graph. With Koin: **Compiler Plugin DSL** ```kotlin val appModule = module { single() single() single() single() single() viewModel() } ``` **Annotations** ```kotlin @Singleton class UserRepository(private val database: Database, private val apiClient: ApiClient) @Singleton class UserService(private val userRepository: UserRepository, private val authRepository: AuthRepository) @KoinViewModel class UserViewModel(private val userService: UserService) : ViewModel() // Database, ApiClient and AuthRepository are annotated the same way @Module @ComponentScan("com.example.app") class AppModule ``` **Constructor / Classic DSL** ```kotlin val appModule = module { singleOf(::Database) singleOf(::ApiClient) singleOf(::UserRepository) singleOf(::AuthRepository) singleOf(::UserService) viewModelOf(::UserViewModel) } ``` The Activity then asks for the top of the graph: ```kotlin class MainActivity : AppCompatActivity() { private val viewModel: UserViewModel by viewModel() } ``` The container creates `UserViewModel` and everything below it, keeps one `Database` for the whole app, and gives a new `UserViewModel` to each screen. [Core Concepts](/docs/intro/core-concepts) explains these pieces. ## How DI libraries build the graph DI libraries differ in when and how they build the graph: | Approach | How it works | Examples | |----------|--------------|----------| | Reflection | Reads constructors at runtime and calls them by reflection | Guice, Spring | | Annotation processing | Generates factory source code at build time | Dagger, Hilt | | Compiler plugin | Rewrites code inside the compiler and checks the graph at build time | Koin Compiler Plugin | | Runtime DSL | You write the factories as Kotlin lambdas, the container runs them at runtime | Koin Classic DSL | Koin keeps a runtime container in all cases. The Compiler Plugin adds the wiring and the build-time checks on top. See [What is Koin?](/docs/intro/what-is-koin) for what this means in practice. ## Service locator and dependency injection The two patterns are often confused. With a **service locator**, a class asks a registry for its dependencies: ```kotlin class UserService : KoinComponent { private val repository: UserRepository by inject() // pulled from the container } ``` With **dependency injection**, the dependencies are given to the class: ```kotlin class UserService( private val repository: UserRepository // pushed in from outside ) ``` | Aspect | Service locator | Dependency injection | |--------|-----------------|----------------------| | Visibility of dependencies | Hidden inside the class | Visible in the constructor | | Testing | Needs the container, or a test version of it | Pass fakes to the constructor | | Coupling | The class depends on the container | The class depends only on its parameters | | In Koin | `get()`, `by inject()`, `KoinComponent` | Constructor parameters resolved by a module | | Good fit | Framework classes you don't construct | Business logic, repositories, services | Koin supports both. Use dependency injection for your own classes, and the service locator style only where a framework creates the object (an `Activity`, a `Fragment`, a Ktor route): ```kotlin // avoid: hidden dependency, needs Koin in tests class UserService : KoinComponent { private val repository: UserRepository = get() } // prefer: explicit dependency class UserService(private val repository: UserRepository) ``` ## What you gain ### Testability ```kotlin class UserService(private val repository: UserRepository) @Test fun getUser() { val repository = mockk() every { repository.findUser("123") } returns testUser val service = UserService(repository) assertEquals(testUser, service.getUser("123")) } ``` A class that receives its dependencies can be tested by calling its constructor. No container is needed. ### Swappable implementations ```kotlin val appModule = module { single { SmtpEmailService() } } val testModule = module { single { FakeEmailService() } } ``` Consumers depend on `EmailService`. Which implementation they get is decided in one place, the module. ### Central configuration ```kotlin startKoin { modules(dataModule, domainModule, presentationModule) } ``` The whole object graph is described by a few modules, usually one per layer or feature, instead of being spread across the code. ### Lifecycle management ```kotlin val appModule = module { single() // one instance for the app factory() // a new instance on every request scope { scoped() // one instance per session } } ``` The container decides how long each object lives, so classes don't manage the lifetime of their dependencies. See [Scopes](/docs/reference/koin-core/scopes). ## Related - [What is Koin?](/docs/intro/what-is-koin): how Koin implements a DI container. - [Core Concepts](/docs/intro/core-concepts): definitions, modules, injection and scopes in Koin. - [Retrieving Dependencies](/docs/reference/koin-core/injection): `get()` and `inject()` in detail. - [Injecting in Tests](/docs/reference/koin-test/testing): test code that uses Koin. --- # What is Koin? Source: https://insert-koin.io/docs/intro/what-is-koin Koin is a dependency injection framework for Kotlin. This page explains how it works, what it costs and what it gives you, and how the project is organized. If dependency injection is new to you, read [What is Dependency Injection?](/docs/intro/what-is-dependency-injection) first. ## How Koin works You describe your classes in modules, start Koin once, and ask for instances where you need them: ```kotlin class ApiService class UserRepository(private val api: ApiService) val appModule = module { single() single() } fun main() { startKoin { modules(appModule) } } ``` Two parts work together: - **Runtime container**: `startKoin` loads your modules into a container. Each definition is a Kotlin function that builds one type. When something asks for a `UserRepository`, Koin runs that function, resolves its constructor parameters from the container, and keeps or discards the instance depending on the definition type (`single`, `factory`, `scoped`). Koin does not build objects by reflection. - **Compile-time checks (optional)**: the [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin) is a Kotlin compiler plugin. It reads your constructors to generate the wiring, then checks at build time that every dependency of the assembled graph is declared. A missing definition becomes a build error instead of a crash. [Core Concepts](/docs/intro/core-concepts) explains modules, definitions, scopes and injection with one running example. ## What the runtime model costs and gives Because the graph lives in a runtime container, Koin can change it while the app runs: - **Dynamic modules**: load and unload modules after start with `loadKoinModules()` and `unloadKoinModules()`, for feature flags or on-demand features. See [Starting Koin](/docs/reference/koin-core/starting-koin). - **Lazy modules**: load part of the graph in the background to reduce startup work. See [Lazy Modules](/docs/reference/koin-core/lazy-modules). - **Scopes created at runtime**: open and close scopes for a session, a screen or a request. See [Scopes](/docs/reference/koin-core/scopes). - **No generated sources**: nothing to commit, nothing to configure per Kotlin Multiplatform target. The same model has costs you should know: - **Startup work**: modules are registered when Koin starts, and every lookup goes through the container. For most apps this is small, but eager definitions (`createdAtStart`) run on the thread that starts Koin. - **Runtime errors without the plugin**: with the Constructor or Classic DSL and no plugin, a missing definition is only found when the code runs. You can catch it in a unit test with [`verify()`](/docs/reference/koin-test/verify), or at build time with the Compiler Plugin. - **Limits of compile-time checks**: the plugin validates the graph assembled at a Koin entry point such as `startKoin`. Modules loaded later with `loadKoinModules()` can't be proven at build time, and a library module with no entry point is only checked when an app assembles it. See [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety). - **Kotlin version coupling**: the Compiler Plugin depends on compiler internals, so each plugin release is verified on a list of Kotlin versions. See [Compiler Plugin Setup](/docs/setup/compiler-plugin). ## Constructor injection and service locator Your classes receive their dependencies through the constructor. Koin only retrieves an instance where it cannot create the object itself, at an entry point: ```kotlin // Koin creates these: dependencies come through the constructor class UserRepository(private val api: UserApi) class UserViewModel(private val repository: UserRepository) : ViewModel() // Android creates the Activity: it retrieves its ViewModel from Koin class UserActivity : AppCompatActivity() { private val viewModel: UserViewModel by viewModel() } ``` The dependency is visible in the signature, and you can test `UserRepository` and `UserViewModel` without Koin. Retrieval functions such as `by inject()`, `by viewModel()` or `koinInject()` belong to entry points: an `Activity`, a `Fragment`, a root Composable, `main()`, a Ktor route, a test. [What is Dependency Injection?](/docs/intro/what-is-dependency-injection) compares the two patterns, and [Retrieving Dependencies](/docs/reference/koin-core/injection) covers `get()` and `inject()`. ## Two styles, one container | Style | Example | Needs | |-------|---------|-------| | Compiler Plugin DSL | `single()` | Koin Compiler Plugin | | Annotations | `@Singleton class UserRepository(...)` | Koin Compiler Plugin, `koin-annotations` | | Constructor DSL | `singleOf(::UserRepository)` | Nothing extra (the plugin adds compile-time checks) | | Classic DSL | `single { UserRepository(get()) }` | Nothing extra (the plugin adds compile-time checks) | Annotations are one style; the Compiler Plugin, Constructor and Classic DSL are the three forms of the other, the Koin DSL. All produce the same definitions in the same container. Pick one style per project. [Choosing your style](/docs/intro/choosing-your-style) compares them and gives a default. ## Annotations status The `koin-annotations` library (`@Singleton`, `@Factory`, `@KoinViewModel`, `@Module`, `@ComponentScan`) is part of the main Koin project: same repository, same version, same BOM. It is not deprecated. What is deprecated is `koin-ksp-compiler`, the KSP processor that used to read these annotations. The Koin Compiler Plugin replaces it, with the same annotations. See [Migrating from KSP to the Compiler Plugin](/docs/migration/from-ksp-to-compiler-plugin). ## Platforms Koin is a Kotlin Multiplatform library. The core runs on every Kotlin target, and integration libraries add platform APIs: | Platform | Main artifact | Start here | |----------|---------------|------------| | Kotlin/JVM | `koin-core` | [Kotlin tutorial](/docs/quickstart/kotlin) | | Android | `koin-android` | [Start Koin on Android](/docs/reference/koin-android/start) | | Jetpack Compose, Compose Multiplatform | `koin-compose`, `koin-compose-viewmodel` | [Koin for Compose](/docs/reference/koin-compose/compose) | | Kotlin Multiplatform (iOS, desktop, web, native) | `koin-core` | [Kotlin Multiplatform Setup](/docs/reference/koin-core/kmp-setup) | | Ktor server | `koin-ktor` | [Koin for Ktor](/docs/reference/koin-ktor/ktor) | The full artifact list is in [Gradle Setup](/docs/setup/gradle). ## The Koin project Koin is open source under the Apache 2.0 license. It is made of: - **Koin libraries**: core, Android, Compose, Ktor, test and annotations, all released under one version. Source: [InsertKoinIO/koin](https://github.com/InsertKoinIO/koin). - **Koin Compiler Plugin**: the Kotlin compiler plugin and its Gradle plugin, with its own version. Source: [InsertKoinIO/koin-compiler-plugin](https://github.com/InsertKoinIO/koin-compiler-plugin). - **Koin IDE Plugin**: navigation and checks in Android Studio and IntelliJ IDEA. See [IDE Plugin](/docs/tooling/ide-plugin). - **Samples**: runnable apps for each tutorial in [InsertKoinIO/koin-getting-started](https://github.com/InsertKoinIO/koin-getting-started). If you know Hilt or Dagger, [Koin vs Hilt](/docs/intro/koin-vs-hilt) compares the two approaches. ## Related - [Core Concepts](/docs/intro/core-concepts): the mental model, with one example built step by step. - [Choosing your style](/docs/intro/choosing-your-style): which declaration style to use. - [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin): what happens at build time. - [Setup](/docs/setup): add Koin to your project. - [Tutorials](/docs/quickstart/kotlin): build a first app. --- # Core Concepts Source: https://insert-koin.io/docs/intro/core-concepts This page builds one small example step by step to explain the ideas behind every other page: definitions, modules, the Koin container, injection, scopes, qualifiers and compile-time checks. Each section is short and links to the page that holds the detail. It assumes you know what dependency injection is (see [What is Dependency Injection?](/docs/intro/what-is-dependency-injection)). Code samples come in three tabs: Compiler Plugin DSL, Annotations, Constructor / Classic DSL. Pick yours, the choice applies to every page. If you are not sure which style to use, read [Choosing your style](/docs/intro/choosing-your-style). ## The example Three plain Kotlin classes. Each one receives what it needs in its constructor and knows nothing about Koin: ```kotlin class ApiService class UserRepository(private val api: ApiService) class UserViewModel(private val repository: UserRepository) : ViewModel() ``` Koin's job is to create `ApiService`, pass it to `UserRepository`, and pass that to `UserViewModel`, without you writing the wiring by hand. ## Definition A **definition** tells Koin how to create one type and how long to keep the instance: **Compiler Plugin DSL** ```kotlin single() single() viewModel() ``` **Annotations** ```kotlin @Singleton class ApiService @Singleton class UserRepository(private val api: ApiService) @KoinViewModel class UserViewModel(private val repository: UserRepository) : ViewModel() ``` **Constructor / Classic DSL** ```kotlin singleOf(::ApiService) singleOf(::UserRepository) viewModelOf(::UserViewModel) ``` The keyword sets the lifetime. `single` keeps one instance for the whole container. `factory` creates a new instance on every request. `viewModel` follows the ViewModel lifecycle. Koin reads the constructor of `UserRepository`, sees it needs an `ApiService`, and resolves it from the container. Detail: [Definitions](/docs/reference/koin-core/definitions). ## Module A **module** groups definitions. You usually have one module per feature or layer: **Compiler Plugin DSL** ```kotlin import org.koin.dsl.module import org.koin.plugin.module.dsl.* val appModule = module { single() single() viewModel() } ``` **Annotations** ```kotlin @Module @ComponentScan("com.example.app") class AppModule ``` `@ComponentScan` collects every annotated class in the package `com.example.app` and its subpackages. **Constructor / Classic DSL** ```kotlin import org.koin.dsl.module import org.koin.core.module.dsl.* val appModule = module { singleOf(::ApiService) singleOf(::UserRepository) viewModelOf(::UserViewModel) } ``` A module is only a description. Nothing is created until Koin starts and someone asks for an instance. Modules can include other modules, so a large app is a tree of small modules. Detail: [Modules](/docs/reference/koin-core/modules). ## The Koin container `startKoin` creates the **container** (a `KoinApplication`) and loads your modules into it. You call it once, at the entry point of your app: **Compiler Plugin DSL** ```kotlin fun main() { startKoin { modules(appModule) } } ``` **Annotations** ```kotlin import org.koin.plugin.module.dsl.startKoin @KoinApplication(modules = [AppModule::class]) class MyApp fun main() { startKoin() } ``` **Constructor / Classic DSL** ```kotlin fun main() { startKoin { modules(appModule) } } ``` On Android you call it in `Application.onCreate()` and pass the Android context with `androidContext(this)`. The container holds the definitions and the instances created so far. `stopKoin()` closes it and releases every `single`. Detail: [Starting Koin](/docs/reference/koin-core/starting-koin), and [Start Koin on Android](/docs/reference/koin-android/start). ## Injection There are two ways an object gets its dependencies. **Constructor injection**: the dependency is a constructor parameter, and Koin passes it when it creates the object. `UserRepository` and `UserViewModel` in this example already use it. This is the default: the class stays plain Kotlin and you can test it by calling the constructor with fakes. **Retrieving from the container**: some classes are created by a framework, not by Koin (an Android `Activity`, a Composable, a Ktor route). They ask the container with `get()` (now) or `inject()` (lazily, on first access): ```kotlin import org.koin.androidx.viewmodel.ext.android.viewModel class UserActivity : AppCompatActivity() { private val viewModel: UserViewModel by viewModel() } ``` ```kotlin import org.koin.compose.viewmodel.koinViewModel @Composable fun UserScreen(viewModel: UserViewModel = koinViewModel()) { ... } ``` Retrieving is the same in every style. Keep it at these entry points: everything below them uses constructor injection. Detail: [Retrieving Dependencies](/docs/reference/koin-core/injection), [Android Entry Points](/docs/reference/koin-android/entry-points), [Koin for Compose](/docs/reference/koin-compose/compose). ## The graph Put together, the container holds this graph: ```text startKoin └── appModule ├── single ApiService ├── single UserRepository ── needs ── ApiService └── viewModel UserViewModel ── needs ── UserRepository UserActivity ── by viewModel() ──> UserViewModel ``` When `UserActivity` asks for `UserViewModel`, Koin creates `ApiService` (once), then `UserRepository` (once), then a `UserViewModel` bound to the Activity's ViewModel lifecycle. ## Scope A `single` lives as long as the container, a `factory` lives as long as the caller keeps it. A **scope** covers the space between: instances that live as long as something else, such as a user session, a screen or a request. Say a `CartRepository` should exist only while a user is logged in: **Compiler Plugin DSL** ```kotlin class UserSession class CartRepository(private val api: ApiService) val sessionModule = module { scope { scoped() } } ``` **Annotations** ```kotlin class UserSession @Scope(UserSession::class) @Scoped class CartRepository(private val api: ApiService) ``` **Constructor / Classic DSL** ```kotlin class UserSession class CartRepository(private val api: ApiService) val sessionModule = module { scope { scopedOf(::CartRepository) } } ``` You open the scope when the session starts and close it when the session ends: ```kotlin // inside a KoinComponent val sessionScope = getKoin().createScope("session-42") val cart: CartRepository = sessionScope.get() sessionScope.close() // releases CartRepository ``` A scoped definition can use definitions from the root container (`ApiService` here). On Android, Koin provides ready-made scopes for Activities, Fragments and ViewModels, so you rarely create scopes by hand. Detail: [Scopes](/docs/reference/koin-core/scopes), and [Android Scopes](/docs/reference/koin-android/scope). ## Qualifier Koin finds a definition by its type. When two definitions provide the same type, a **qualifier** gives each one a name: **Compiler Plugin DSL** ```kotlin interface NetworkClient @Named("auth") class AuthClient : NetworkClient @Named("public") class PublicClient : NetworkClient class UserRepository(@Named("auth") private val client: NetworkClient) val networkModule = module { single() bind NetworkClient::class single() bind NetworkClient::class single() } ``` **Annotations** ```kotlin @Singleton @Named("auth") class AuthClient : NetworkClient @Singleton @Named("public") class PublicClient : NetworkClient @Singleton class UserRepository(@Named("auth") private val client: NetworkClient) ``` **Constructor / Classic DSL** ```kotlin val networkModule = module { single(named("auth")) { AuthClient() } single(named("public")) { PublicClient() } single { UserRepository(get(named("auth"))) } } ``` Detail: [Qualifiers](/docs/reference/koin-core/qualifiers). ## Compile-time checks Without the Compiler Plugin, a missing definition shows up when the code runs: `get()` throws `NoDefinitionFoundException`. With the [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin), the same mistake fails the build. If you remove `single()` from `appModule`, compilation stops with: ```text [Koin][KOIN-D001] Missing dependency: ApiService required by: UserRepository (parameter 'api') in module: ... ``` The plugin checks the full graph at each entry point (`startKoin`, `@KoinApplication`, Ktor's `install(Koin)`) and every `get()`, `inject()` or `koinViewModel()` call. With the Constructor or Classic DSL and no plugin, you get a similar check in a unit test with `verify()`. Detail: [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety), [Verifying your Koin configuration](/docs/reference/koin-test/verify). ## Related - [Choosing your style](/docs/intro/choosing-your-style): which declaration style to use. - [Setup](/docs/setup): add Koin and the Compiler Plugin to your build. - [Tutorials](/docs/quickstart/kotlin): build a complete app with these concepts. - [Definitions](/docs/reference/koin-core/definitions): every definition type in detail. - [Scopes](/docs/reference/koin-core/scopes): lifecycles beyond single and factory. --- # Choosing your style Source: https://insert-koin.io/docs/intro/choosing-your-style Koin offers two styles to declare definitions, both filling the same container: **annotations** on your classes, or the **Koin DSL** in `module { }` blocks. The DSL comes in three forms: the Compiler Plugin DSL (`single()`), the Constructor DSL (`singleOf(::T)`) and the Classic DSL (`single { T(get()) }`). The choice changes how you write modules, not how Koin works at runtime. This page shows each style, its requirements and tradeoffs, and recommends a default. It assumes you know what a definition and a module are (see [Core Concepts](/docs/intro/core-concepts)). ## The styles side by side The same module in each style: **Compiler Plugin DSL** ```kotlin import org.koin.dsl.module import org.koin.plugin.module.dsl.* val appModule = module { single() single() bind UserRepository::class viewModel() } ``` You name the type. The [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin) reads its constructor and generates the wiring. **Annotations** ```kotlin @Singleton class ApiService @Singleton class UserRepositoryImpl(private val api: ApiService) : UserRepository @KoinViewModel class UserViewModel(private val repository: UserRepository) : ViewModel() @Module @ComponentScan("com.example.app") class AppModule ``` You annotate each class. `@ComponentScan` gathers them into a module, and the Compiler Plugin generates the wiring. Interfaces are bound automatically. **Constructor / Classic DSL** Constructor DSL, with constructor references: ```kotlin import org.koin.dsl.module import org.koin.core.module.dsl.* val appModule = module { singleOf(::ApiService) singleOf(::UserRepositoryImpl) bind UserRepository::class viewModelOf(::UserViewModel) } ``` Classic DSL, with the constructor call written by hand: ```kotlin val appModule = module { single { ApiService() } single { UserRepositoryImpl(get()) } viewModel { UserViewModel(get()) } } ``` Both forms work without the compiler plugin. When the plugin is applied, they are checked at build time too. ## Requirements | | Compiler Plugin DSL | Annotations | Constructor / Classic DSL | |---|---|---|---| | Koin version | 4.2.0+ | 4.2.0+ | Any | | Kotlin version | 2.3.20+ (K2) | 2.3.20+ (K2) | Any version supported by your Koin version | | Gradle plugin | `io.insert-koin.compiler.plugin` (required) | `io.insert-koin.compiler.plugin` (required) | Optional: adds compile-time checks | | Extra dependency | `koin-annotations` only for parameter annotations (`@Named`, `@InjectedParam`) | `koin-annotations` | None | | Imports | `org.koin.plugin.module.dsl.*` | `org.koin.core.annotation.*` | `org.koin.core.module.dsl.*` (Constructor), `org.koin.dsl.*` (Classic) | Each Compiler Plugin release is verified on a list of Kotlin versions. Plugin 1.2.1 is verified on Kotlin 2.3.20, 2.4.0, 2.4.10 and 2.4.20. Installation steps are in [Compiler Plugin Setup](/docs/setup/compiler-plugin). :::warning The Compiler Plugin DSL functions (`single()`, `factory()`, `create(::T)`) are stubs. Without the Gradle plugin applied, the code compiles but throws `NotImplementedError` at runtime. Apply the plugin in every Gradle module that uses them. ::: ## Tradeoffs ### Compiler Plugin DSL - **Compile-time checks**: the full graph and every `get()` call site are validated at build time. - **No wiring code**: no `get()`, no constructor references. Adding a constructor parameter needs no module change. - **Explicit modules**: you see every definition of a module in one place, and you can use Kotlin code (conditions, loops) around them. - **Parameter annotations**: qualifiers and injected parameters are declared on the class (`@Named`, `@InjectedParam`), so the class depends on `koin-annotations`. - **Kotlin coupling**: you need a recent K2 compiler, and a new Kotlin release may need a new plugin release. ### Annotations - **Compile-time checks**: same as the Compiler Plugin DSL. - **Definition next to the class**: the lifetime and bindings are visible where the class is written. Teams coming from Hilt, Dagger or Spring find the model familiar. - **Automatic binding**: a class is bound to all its supertypes unless you list `binds`. - **Scanning configuration**: definitions are found by package. You need `@Module` and `@ComponentScan` with the right packages, and `@Configuration` or `@KoinApplication` to assemble modules across Gradle modules. A class outside the scanned packages is not part of the module. The compile-time check reports it only if another definition needs it. - **Gaps**: some options exist only in the DSL, such as the `onClose` callback. You write those definitions in a DSL module. - **Kotlin coupling**: same as the Compiler Plugin DSL. ### Constructor DSL and Classic DSL - **Works everywhere**: the compiler plugin is optional, no Kotlin version constraint beyond Koin's own. - **Compile-time checks with the plugin**: since Compiler Plugin 1.2.0, applying the plugin checks `singleOf(::T)`, `factoryOf(::T)`, `scopedOf(::T)` and `viewModelOf(::T)` like `single()`, and hand-written lambdas through their `get()` calls. Existing modules get compile-time checks without a rewrite. - **Full control (Classic DSL)**: the lambda is plain Kotlin, so you can call builders, read configuration or choose an implementation at runtime. - **Runtime errors without the plugin**: a missing definition is found when the code runs. Use [`verify()`](/docs/reference/koin-test/verify) in a unit test to catch it earlier. - **Wiring to maintain**: `single { UserRepository(get(), get()) }` must follow constructor changes by hand. `singleOf(::UserRepository)` follows them, but needs explicit calls for nullable, lazy or qualified parameters. ## Which one to pick Pick one style for the project and state it: annotations or the DSL. For a new project on Kotlin 2.3.20 or later, use the **Compiler Plugin DSL**. It gives compile-time checks, keeps DI out of your classes and keeps modules as explicit Kotlin code. If your team prefers to declare definitions on the class, as with Hilt or Dagger, use **annotations**: they get the same checks and are JSR-330 compatible (`@Inject`, `@Singleton`, `@Named`). Keep the **Constructor or Classic DSL** if you can't use a recent Kotlin version, if you build a library that must not require a compiler plugin from its users, or if your existing modules work and you don't want to change them. Apply the Compiler Plugin to get compile-time checks on them without a rewrite. Use a Classic DSL lambda wherever a definition needs custom logic. ## Mixing styles All styles produce the same definitions, so one project can use several. Prefer one style per project. If you mix annotations and the DSL, keep one style per module. Common cases: - **Compiler Plugin DSL and Classic DSL in one module**: write `single()` for most definitions, and a lambda where you need custom logic. Both are DSL forms, so this is not mixing styles. - **Annotations with a few DSL modules**: start from your `@KoinApplication` class and add DSL modules in the configuration block. - **DSL start with annotated modules**: load a `@Module` class into a regular `startKoin`. ```kotlin import org.koin.plugin.module.dsl.module import org.koin.plugin.module.dsl.startKoin // annotated application, plus DSL modules startKoin { modules(legacyModule) } // DSL application, plus an annotated module startKoin { modules(appModule) module() } ``` `@Module(includes = [...])` and `@KoinApplication(modules = [...])` only accept `@Module` classes, not DSL `module { }` values. See [Modules](/docs/reference/koin-core/modules) and [Starting Koin](/docs/reference/koin-core/starting-koin) for the full rules. ## The KSP processor is deprecated Before the Compiler Plugin, annotations were processed by `koin-ksp-compiler`, a KSP processor. That processor is deprecated and will be removed in a future Koin version. The annotations themselves are not deprecated: `koin-annotations` is part of the main Koin project and ships with each Koin version. If you use KSP today, your annotated classes stay the same and only the build setup and the start code change. See [Migrating from KSP to the Compiler Plugin](/docs/migration/from-ksp-to-compiler-plugin). ## Tabs on every page Code samples in these docs use the same three tabs: Compiler Plugin DSL, Annotations, Constructor / Classic DSL. When you select a tab, the choice is saved in your browser and applied on every page. Samples that are the same in all styles, such as `by inject()` in an Activity, are shown once without tabs. ## Related - [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin): how the plugin works and what it validates. - [Compiler Plugin Setup](/docs/setup/compiler-plugin): install the Gradle plugin. - [Definitions](/docs/reference/koin-core/definitions): every definition type, in every style. - [DSL Reference](/docs/reference/koin-core/dsl) and [Annotations Reference](/docs/reference/koin-annotations/annotations-inventory): every keyword and annotation. - [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin): move from `koin-ksp-compiler`. --- # Koin Compiler Plugin Source: https://insert-koin.io/docs/intro/koin-compiler-plugin The Koin Compiler Plugin is a Kotlin compiler plugin that runs inside the Kotlin compiler (K2). It writes the constructor wiring for your definitions and checks your dependency graph at build time. It powers both the Compiler Plugin DSL and annotations. This page explains what it does and how. To install it, see [Compiler Plugin Setup](/docs/setup/compiler-plugin). To compare it with the Constructor and Classic DSL, see [Choosing your style](/docs/intro/choosing-your-style). ## What it does to your code You write the type, the plugin writes the constructor call: **Compiler Plugin DSL** ```kotlin class UserRepository(private val api: ApiService, private val cache: UserCache) val appModule = module { single() } ``` **Annotations** ```kotlin @Singleton class UserRepository(private val api: ApiService, private val cache: UserCache) ``` **Constructor / Classic DSL** The Classic DSL does not need the plugin: you write the wiring yourself. The Constructor DSL (`singleOf(::T)`) doesn't need it either. ```kotlin val appModule = module { single { UserRepository(get(), get()) } } ``` If the plugin is applied, it still checks these `get()` calls and `singleOf(::T)` definitions at build time. During compilation, the plugin replaces `single()` (or the `@Singleton` class) with the equivalent of: ```kotlin single { UserRepository(get(), get()) } ``` The generated code is the same runtime code the Classic DSL uses. Nothing changes at runtime: definitions go into the same container, and Koin resolves them the same way. Each parameter type is handled: nullable types use `getOrNull()`, `Lazy` uses `inject()`, `List` uses `getAll()`, and annotated parameters (`@Named`, `@InjectedParam`, `@Property`) use the matching call. The full table is in [Definitions](/docs/reference/koin-core/definitions#constructor-parameters). In DSL style, the module says where a class is registered, and annotations on the class's parameters say how they are resolved: ```kotlin class UserPresenter( @InjectedParam val userId: String, @Named("remote") val api: ApiService, val repository: UserRepository, ) val appModule = module { factory() } ``` ## How it works The plugin hooks into two phases of the Kotlin K2 compiler: ```text Kotlin sources │ ▼ FIR (frontend) finds @Module, @ComponentScan, @Configuration and declares the generated module properties and cross-module hints │ ▼ IR (backend) 1. collects annotated definitions and fills the modules 2. rewrites DSL calls: single() becomes single { T(get()) } 3. at entry points (startKoin, @KoinApplication), assembles the full graph and validates it 4. validates get(), inject(), koinViewModel() call sites │ ▼ Bytecode (JVM, Android, Native, JS, Wasm) ``` No source file is generated in your project. To see across Gradle modules, the plugin adds small synthetic marker functions ("hints") to each compiled module. A downstream module reads them to find definitions declared in its dependencies. This is why every Gradle module that declares Koin definitions must apply the plugin. ## What it validates The plugin validates the graph at each Koin entry point: `startKoin`, `koinApplication`, `@KoinApplication`, `KoinApplication.withConfiguration()` and Ktor's `install(Koin) {}`. For each definition it checks that every non-nullable constructor parameter has a matching definition, with the right qualifier and in a reachable scope. It also checks every `get()`, `inject()` and `koinViewModel()` call. A missing dependency fails the build: ```text [Koin][KOIN-D001] Missing dependency: ApiService required by: UserRepository (parameter 'api') in module: ... ``` The full list of checks, error codes and the `@Provided` escape hatch are in [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety). ## Limits - **Runtime-loaded modules**: modules added later with `loadKoinModules()` are not part of the graph the plugin sees. Types they provide must be marked `@Provided`. - **Library modules alone**: a Gradle module with no Koin entry point is not validated on its own. It is checked when an app module assembles it. - **Incremental compilation**: like other IR compiler plugins, some changes (moving classes between scanned packages, changing qualifiers) can leave stale results. A clean build fixes them. See [Compiler Plugin Setup](/docs/setup/compiler-plugin) for details. - **Kotlin versions**: the plugin uses compiler APIs that change between Kotlin releases. Each plugin release is verified on a list of Kotlin versions, and other versions print a warning. ## Requirements - Kotlin 2.3.20 or later (K2 compiler). Plugin 1.2.1 is verified on Kotlin 2.3.20, 2.4.0, 2.4.10 and 2.4.20. - Koin 4.2.0 or later. - Gradle plugin `io.insert-koin.compiler.plugin`, applied in every Gradle module that declares definitions. The Compiler Plugin DSL lives in the package `org.koin.plugin.module.dsl`, shipped with `koin-core`. The Classic DSL stays in `org.koin.dsl`, the Constructor DSL in `org.koin.core.module.dsl`. The plugin replaces the deprecated KSP processor `koin-ksp-compiler`, with the same annotations. See [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin). The source is on GitHub: [InsertKoinIO/koin-compiler-plugin](https://github.com/InsertKoinIO/koin-compiler-plugin). ## Related - [Compiler Plugin Setup](/docs/setup/compiler-plugin): install and configure the plugin. - [Choosing your style](/docs/intro/choosing-your-style): annotations or the DSL (Compiler Plugin, Constructor or Classic DSL). - [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety): every check and error code. - [Compiler Plugin Options](/docs/reference/koin-annotations/options): every Gradle option. - [Definitions](/docs/reference/koin-core/definitions): how constructor parameters are resolved. --- # Setup Source: https://insert-koin.io/docs/setup This section explains what to add to your Gradle build to use Koin. Pick your platform below, then follow the linked section of [Gradle Setup](/docs/setup/gradle). If you have not chosen a declaration style yet, read [Choosing your style](/docs/intro/choosing-your-style) first: it decides whether you also need the Compiler Plugin. ## What to install | Platform | Artifacts | Setup | |----------|-----------|-------| | Kotlin/JVM | `koin-core` | [Kotlin/JVM](/docs/setup/gradle#kotlin) | | Android | `koin-android` | [Android](/docs/setup/gradle#android) | | Android with Jetpack Compose | `koin-android`, `koin-compose`, `koin-compose-viewmodel` | [Jetpack Compose](/docs/setup/gradle#compose-android) | | Compose Multiplatform | `koin-compose`, `koin-compose-viewmodel` | [Compose Multiplatform](/docs/setup/gradle#compose) | | Kotlin Multiplatform | `koin-core` in `commonMain` | [Kotlin Multiplatform](/docs/setup/gradle#kotlin-multiplatform) | | Ktor | `koin-ktor`, `koin-logger-slf4j` | [Ktor](/docs/setup/gradle#ktor) | | Tests | `koin-test`, `koin-test-junit4` or `koin-test-junit5` | [Testing](/docs/setup/gradle#testing) | ## Recommended setup For a new project: 1. **Koin BOM**: import `io.insert-koin:koin-bom` and declare Koin artifacts without versions, so they always match. See [Gradle Setup](/docs/setup/gradle). 2. **Koin Compiler Plugin**: apply the Gradle plugin `io.insert-koin.compiler.plugin` to get the Compiler Plugin DSL or annotations, with compile-time checks. It needs Kotlin 2.3.20 or later. See [Compiler Plugin Setup](/docs/setup/compiler-plugin). If you use the Constructor or Classic DSL only, step 1 is enough. Step 2 is still recommended: it adds compile-time checks to those definitions. :::warning The KSP processor `koin-ksp-compiler` is deprecated. Its setup is kept in [KSP Processor Setup](/docs/setup/annotations-ksp) for existing projects only. New projects use the Compiler Plugin. ::: ## Versions | Component | Current version | Kotlin | |-----------|-----------------|----------| | Koin (all libraries, including `koin-annotations`) | 4.2.2 | Built with 2.3.20 | | Koin Compiler Plugin | 1.2.1 | Verified on 2.3.20, 2.4.0, 2.4.10, 2.4.20 (needs Koin 4.2.0+) | Latest published versions: - Koin: [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core?label=latest)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) - Koin Compiler Plugin: [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-compiler-plugin?label=latest)](https://mvnrepository.com/artifact/io.insert-koin/koin-compiler-plugin) Older Koin lines: | Koin | Kotlin | Compiler Plugin | |------|--------|-----------------| | 4.2.x | 2.3.20+ | Yes | | 4.1.x | 2.1+ | No, KSP processor only | | 4.0.x | 1.9+ | No, KSP processor only | | 3.5.x | 1.8+ | No | What changed between versions and how to upgrade is in [Releases](/docs/support/releases). ## Related - [Gradle Setup](/docs/setup/gradle): the BOM and every Koin artifact. - [Compiler Plugin Setup](/docs/setup/compiler-plugin): install and configure the plugin. - [Choosing your style](/docs/intro/choosing-your-style): which style needs what. - [Tutorials](/docs/quickstart/kotlin): a first app on each platform. - [Releases](/docs/support/releases): versions and upgrade notes. --- # Gradle Setup Source: https://insert-koin.io/docs/setup/gradle This page lists the Gradle dependencies for each platform and every published Koin artifact. Samples use the Kotlin DSL (`build.gradle.kts`) and a version catalog. To add compile-time checks and the Compiler Plugin DSL, also follow [Compiler Plugin Setup](/docs/setup/compiler-plugin). ## Versions All Koin libraries, including `koin-annotations`, share one version. The current stable version is 4.2.2. - Koin: [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core?label=latest)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) All artifacts are on [Maven Central](https://central.sonatype.com/search?q=io.insert-koin) under the group `io.insert-koin`. Version history and upgrade notes are in [Releases](/docs/support/releases). ## Koin BOM The Koin BOM (bill of materials) pins every Koin library to the same version. You declare the BOM version once and add Koin libraries without a version. When you update the BOM, all Koin libraries move together. In `gradle/libs.versions.toml`: ```toml [versions] koin = "4.2.2" [libraries] koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" } koin-core = { module = "io.insert-koin:koin-core" } koin-android = { module = "io.insert-koin:koin-android" } koin-compose = { module = "io.insert-koin:koin-compose" } koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" } koin-compose-viewmodel-navigation = { module = "io.insert-koin:koin-compose-viewmodel-navigation" } koin-ktor = { module = "io.insert-koin:koin-ktor" } koin-logger-slf4j = { module = "io.insert-koin:koin-logger-slf4j" } koin-annotations = { module = "io.insert-koin:koin-annotations" } koin-test = { module = "io.insert-koin:koin-test" } koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4" } ``` In your module's `build.gradle.kts`: ```kotlin dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.android) } ``` Without a version catalog: ```kotlin dependencies { implementation(platform("io.insert-koin:koin-bom:4.2.2")) implementation("io.insert-koin:koin-android") testImplementation("io.insert-koin:koin-test-junit4") } ``` A version written on one dependency overrides the BOM for that dependency only. Avoid it unless you need a fix from a newer release of one library. ### Without the BOM You can also put the version on each library. This is what the [Koin samples](https://github.com/InsertKoinIO/koin-getting-started) do, and it works the same in Kotlin Multiplatform source sets: ```toml [versions] koin = "4.2.2" [libraries] koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } ``` Keep a single `koin` version for all Koin libraries: mixing versions is not supported. ## Kotlin/JVM {#kotlin} ```kotlin dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.core) } ``` Then start Koin in `main`. See [Starting Koin](/docs/reference/koin-core/starting-koin) and the [Kotlin tutorial](/docs/quickstart/kotlin). ## Android {#android} ```kotlin dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.android) } ``` `koin-android` includes `koin-core` and the ViewModel support. Start Koin in your `Application` class: see [Start Koin on Android](/docs/reference/koin-android/start). Optional Android libraries: | Artifact | Adds | |----------|------| | `koin-androidx-workmanager` | WorkManager workers: see [WorkManager](/docs/reference/koin-android/workmanager) | | `koin-androidx-navigation` | ViewModels scoped to a Navigation graph (Fragments) | | `koin-androidx-startup` | Start Koin with AndroidX App Startup | | `koin-android-compat` | Java helpers to inject from Java classes | | `koin-dagger-bridge` | Use Dagger components from Koin during a migration | ## Android with Jetpack Compose {#compose-android} ```kotlin dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.android) implementation(libs.koin.compose) implementation(libs.koin.compose.viewmodel) } ``` `koin-androidx-compose` is an Android-only artifact that brings `koin-compose` and `koin-compose-viewmodel` in one dependency. Either setup works. For navigation, add one of: | Artifact | Navigation library | |----------|--------------------| | `koin-androidx-compose-navigation` | Navigation Compose 2, Android only | | `koin-compose-viewmodel-navigation` | Navigation Compose 2, multiplatform | | `koin-compose-navigation3` | Navigation 3: see [Navigation 3](/docs/reference/koin-compose/navigation3) | See [Koin for Compose](/docs/reference/koin-compose/compose) for the APIs. ## Compose Multiplatform {#compose} In the shared module, add the Compose libraries to `commonMain`. In multiplatform source sets, use catalog entries that carry the version (see [Without the BOM](#without-the-bom)): ```kotlin kotlin { sourceSets { commonMain.dependencies { implementation(libs.koin.core) implementation(libs.koin.compose) implementation(libs.koin.compose.viewmodel) implementation(libs.koin.compose.viewmodel.navigation) // if you use Navigation Compose } } } ``` On Android, `koin-compose` brings `koin-android`, so you don't need to add it. See the [Compose Multiplatform tutorial](/docs/quickstart/cmp). ## Kotlin Multiplatform {#kotlin-multiplatform} In the shared module's `build.gradle.kts`, with catalog entries that carry the version (see [Without the BOM](#without-the-bom)): ```kotlin kotlin { sourceSets { commonMain.dependencies { implementation(libs.koin.core) } androidMain.dependencies { implementation(libs.koin.android) } commonTest.dependencies { implementation(libs.koin.test) } } } ``` `koin-core` supports JVM, Android, Apple targets (iOS, macOS, tvOS, watchOS), Linux, Windows, JS and Wasm (`wasmJs`). Project structure and platform-specific definitions are covered in [Kotlin Multiplatform Setup](/docs/reference/koin-core/kmp-setup). ## Ktor {#ktor} ```kotlin dependencies { implementation(platform(libs.koin.bom)) implementation(libs.koin.ktor) implementation(libs.koin.logger.slf4j) } ``` Install the Koin plugin in your Ktor application: see [Koin for Ktor](/docs/reference/koin-ktor/ktor). ## Testing {#testing} ```kotlin dependencies { testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit4) // or koin-test-junit5 } ``` For Android instrumented tests, add `koin-android-test` to `androidTestImplementation`. See [Injecting in Tests](/docs/reference/koin-test/testing) and [Android Instrumented Testing](/docs/reference/koin-android/instrumented-testing). ## All artifacts | Artifact | Platforms | Description | |----------|-----------|-------------| | `koin-bom` | All | Bill of materials for every artifact below | | `koin-core` | All | Container, DSL, scopes, Compiler Plugin DSL | | `koin-core-coroutines` | All | Lazy modules and background loading | | `koin-core-viewmodel` | All | ViewModel definitions for Android and Compose Multiplatform | | `koin-annotations` | All | Annotations for the Compiler Plugin (`@Singleton`, `@Module`, `@Named`, ...) | | `koin-android` | Android | Android context, Activity and Fragment APIs, ViewModel | | `koin-android-compat` | Android | Java compatibility helpers | | `koin-androidx-navigation` | Android | Navigation graph scoped ViewModels | | `koin-androidx-workmanager` | Android | WorkManager integration | | `koin-androidx-startup` | Android | AndroidX App Startup integration | | `koin-dagger-bridge` | Android | Access Dagger components from Koin | | `koin-compose` | All Compose targets | `koinInject()`, `KoinApplication` and Compose context | | `koin-compose-viewmodel` | All Compose targets | `koinViewModel()` | | `koin-compose-viewmodel-navigation` | All Compose targets | ViewModels scoped to a Navigation Compose back stack entry | | `koin-compose-navigation3` | All Compose targets | Navigation 3 integration | | `koin-androidx-compose` | Android | Bundle of `koin-compose` and `koin-compose-viewmodel` for Android | | `koin-androidx-compose-navigation` | Android | Navigation Compose 2 for Android | | `koin-ktor` | JVM, JS, Wasm, iOS, macOS (Ktor server targets) | Ktor server plugin | | `koin-logger-slf4j` | JVM | SLF4J logger | | `koin-test` | All | Test API: `KoinTest`, `verify()` | | `koin-test-coroutines` | JVM | Verification for lazy modules | | `koin-test-junit4` | JVM | JUnit 4 rules | | `koin-test-junit5` | JVM | JUnit 5 extensions | | `koin-android-test` | Android | Instrumented test helpers | The Koin Compiler Plugin is a Gradle plugin, not a library: it has its own version. See [Compiler Plugin Setup](/docs/setup/compiler-plugin). ## Related - [Compiler Plugin Setup](/docs/setup/compiler-plugin): add the Compiler Plugin and compile-time checks. - [Setup](/docs/setup): what to install for each platform. - [Starting Koin](/docs/reference/koin-core/starting-koin): start the container once dependencies are in place. - [Tutorials](/docs/quickstart/kotlin): a first app on each platform. - [Releases](/docs/support/releases): versions and upgrade notes. --- # Compiler Plugin Setup Source: https://insert-koin.io/docs/setup/compiler-plugin This page installs the Koin Compiler Plugin, the Kotlin compiler plugin behind the Compiler Plugin DSL and annotations. It covers single-module, multi-module and Kotlin Multiplatform builds, the main options, and setup problems. To learn what the plugin does, read [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin). Koin libraries themselves are listed in [Gradle Setup](/docs/setup/gradle). ## Requirements - Kotlin 2.3.20 or later (K2 compiler). - Koin 4.2.0 or later. - Gradle 8 or later. Current versions: - Koin: [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core?label=latest)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) - Koin Compiler Plugin: [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-compiler-plugin?label=latest)](https://mvnrepository.com/artifact/io.insert-koin/koin-compiler-plugin) The plugin has its own version, separate from Koin. `koin-annotations` follows the Koin version. ## Install ### 1. Declare the plugin In `gradle/libs.versions.toml`: ```toml [versions] koin = "4.2.2" koin-plugin = "1.2.1" [libraries] koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" } [plugins] koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } ``` If you use the [Koin BOM](/docs/setup/gradle#koin-bom), drop `version.ref` from the libraries. The plugin is not part of the BOM and keeps its version. ### 2. Plugin repositories The plugin is published on Maven Central and the Gradle Plugin Portal. In `settings.gradle.kts`: ```kotlin pluginManagement { repositories { mavenCentral() gradlePluginPortal() } } ``` ### 3. Apply the plugin In the `build.gradle.kts` of each Gradle module that declares Koin definitions: ```kotlin plugins { alias(libs.plugins.koin.compiler) } dependencies { implementation(libs.koin.core) // or koin-android, koin-ktor, ... implementation(libs.koin.annotations) // for annotations, and for @Named or @InjectedParam in DSL style } ``` The Compiler Plugin DSL (`single()`, `factory()`, `viewModel()`) ships with the Koin libraries, in the package `org.koin.plugin.module.dsl`. You need `koin-annotations` only if you use annotations, including parameter annotations in DSL style. :::tip `@KoinViewModel` and `@KoinWorker` need their runtime library on the classpath: `koin-core-viewmodel` (included in `koin-android` and `koin-compose-viewmodel`) and `koin-androidx-workmanager`. If one is missing, the build fails with an error that names the artifact. ::: ### 4. Check that it works Turn on the plugin logs for one build: ```kotlin koinCompiler { userLogs = true } ``` The build output lists each definition the plugin detected. Turn it off again once you have checked. Then start Koin as described in [Starting Koin](/docs/reference/koin-core/starting-koin), with `startKoin { }` or, for annotations, `startKoin()`. ## Multi-module projects Apply the plugin in every Gradle module that declares definitions, not only in the app module: ```kotlin // feature/build.gradle.kts plugins { alias(libs.plugins.koin.compiler) } dependencies { implementation(libs.koin.core) implementation(libs.koin.annotations) } ``` ```kotlin // app/build.gradle.kts plugins { alias(libs.plugins.koin.compiler) } dependencies { implementation(project(":feature")) implementation(libs.koin.android) implementation(libs.koin.annotations) } ``` Each module compiled with the plugin carries metadata about its definitions. The app module reads it to check the full graph at `startKoin`. A library module without the plugin is invisible to these checks. How to assemble modules across Gradle modules (`includes`, `@Configuration`) is covered in [Modules](/docs/reference/koin-core/modules) and [Multi-Module Android Apps](/docs/reference/koin-android/multi-module). ## Kotlin Multiplatform Apply the plugin once on the shared module and add the libraries to `commonMain`. There is no per-target configuration: ```kotlin // shared/build.gradle.kts plugins { alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.koin.compiler) } kotlin { sourceSets { commonMain.dependencies { implementation(libs.koin.core) implementation(libs.koin.annotations) } } } ``` See [Kotlin Multiplatform Setup](/docs/reference/koin-core/kmp-setup) for project structure. ## Options The `koinCompiler` block configures the plugin. The defaults fit most projects: ```kotlin koinCompiler { compileSafety = true // validate the graph at build time skipDefaultValues = true // use Kotlin default values instead of injecting userLogs = false // log detected definitions } ``` Every option, including `strictSafety`, `unsafeDslChecks`, `logSeverity` and `debugLogs`, is described in [Compiler Plugin Options](/docs/reference/koin-annotations/options). ## Kotlin version compatibility Each plugin release is verified on a list of Kotlin versions: | Kotlin | Koin Compiler Plugin | |--------|----------------------| | 2.3.20, 2.4.0, 2.4.10 | 1.2.0+ | | 2.4.20 | 1.2.1+ | On a Kotlin version that is not in the list, the plugin prints a warning and the build continues. :::warning On Kotlin 2.4.20, plugin 1.2.0 fails with `NoSuchMethodError` during IR generation. Use 1.2.1 or later. ::: ## Troubleshooting ### Plugin not found Gradle can't resolve `io.insert-koin.compiler.plugin`. Check that `mavenCentral()` and `gradlePluginPortal()` are in `pluginManagement.repositories` in `settings.gradle.kts`. ### NotImplementedError at runtime `single()`, `factory()` and `create(::T)` are placeholders that the plugin replaces. If the plugin is not applied to the Gradle module that contains them, the code compiles and throws `NotImplementedError` when the module is created. Apply the plugin to that module. ### Wrong imports The Compiler Plugin DSL and the Constructor DSL have functions with the same names in different packages: ```kotlin // Compiler Plugin DSL import org.koin.plugin.module.dsl.* // Constructor DSL: singleOf, factoryOf, viewModelOf import org.koin.core.module.dsl.* // both import org.koin.dsl.module ``` ### Stale results after a refactor Like other Kotlin IR plugins (the Compose compiler, for example), the Koin Compiler Plugin can produce stale results with incremental compilation. Symptoms: - A compile safety error that should not appear, or none after you removed a definition. - `NoSuchMethodError` or `ClassNotFoundException` at runtime after a refactor. It usually follows these changes: - Changing an annotation on a class (`@Singleton` to `@Factory`, adding or removing `@Named`). - Moving classes between packages scanned by `@ComponentScan`. - Changing module `includes` or `@Configuration` labels. - Adding or removing definitions in a library module another module depends on. Run a clean build: `./gradlew clean build`, or in Android Studio, Build > Clean Project then Build > Rebuild Project. For changes inside `module { }` lambdas, the plugin turns on `strictSafety` for modules that contain an entry point (`startKoin`, `koinApplication`, `@KoinApplication`). It re-runs the full graph check on each build of those modules. See [`strictSafety`](/docs/reference/koin-annotations/options). ### Missing dependency reported across modules If the plugin reports a missing dependency that a library module does declare: 1. Apply the plugin to the library module too. Without it, the library carries no metadata. 2. Make sure the library is built before the module that uses it. `implementation(project(":lib"))` normally does this. 3. Run a clean build after adding the plugin to a library for the first time. 4. Use plugin 1.2.1 or later. Earlier versions missed definitions two or more `implementation` levels away and merged `@Named` providers across modules. If you turned `compileSafety` off because of false `KOIN-D001` errors, turn it back on. ## Moving to the Compiler Plugin - **From the Constructor or Classic DSL**: apply the plugin. Your existing `singleOf(::T)` definitions and `get()` calls are checked at build time without changes. You can then replace them with `single()` module by module. See [Choosing your style](/docs/intro/choosing-your-style). - **From the KSP processor**: remove KSP and `koin-ksp-compiler`, apply the plugin, and replace the generated `.module` extensions with `startKoin()`. Your annotations stay the same. See [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin). ## Related - [Koin Compiler Plugin](/docs/intro/koin-compiler-plugin): what the plugin does and how it works. - [Compiler Plugin Options](/docs/reference/koin-annotations/options): every Gradle option. - [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety): every check and error code. - [Gradle Setup](/docs/setup/gradle): Koin libraries and the BOM. - [Starting Koin](/docs/reference/koin-core/starting-koin): typed start APIs such as `startKoin()`. --- # KSP Processor Setup (Deprecated) Source: https://insert-koin.io/docs/setup/annotations-ksp This page documents the Gradle setup of `koin-ksp-compiler`, the KSP processor that used to read Koin annotations. It is kept for projects that still use it. New projects use the [Koin Compiler Plugin](/docs/setup/compiler-plugin). :::warning `koin-ksp-compiler` is deprecated and will be removed in a future Koin version. The annotations are not deprecated: `koin-annotations` is part of the main Koin project and is processed by the Koin Compiler Plugin. Only the processor changes. See [Migrating from KSP to the Compiler Plugin](/docs/migration/from-ksp-to-compiler-plugin). ::: ## When to keep the KSP processor Keep it only for a short time, if: - **Kotlin version**: your project can't move to Kotlin 2.3.20 or later yet, which the Compiler Plugin requires. - **Migration in progress**: you need to ship before you can switch the build. Compared with the Compiler Plugin, the KSP processor generates visible source files, needs a KSP configuration per Kotlin Multiplatform target, and uses generated extensions such as `AppModule().module` to start Koin. ## Gradle setup ```kotlin // build.gradle.kts plugins { id("com.google.devtools.ksp") version "$ksp_version" } dependencies { implementation(platform("io.insert-koin:koin-bom:$koin_version")) implementation("io.insert-koin:koin-core") implementation("io.insert-koin:koin-annotations:$koin_ksp_version") ksp("io.insert-koin:koin-ksp-compiler:$koin_ksp_version") } ``` With KSP, `koin-annotations` and `koin-ksp-compiler` use the Koin Annotations version (`$koin_ksp_version`), not the Koin version. With the Compiler Plugin, `koin-annotations` follows the Koin version. ### Version compatibility | Koin Annotations | KSP | Kotlin | |------------------|-----|--------| | 1.4 | 1.9 | 1.9 | | 2.0 | 2.0 | 2.0 | | 2.1, 2.2 | 2.1, 2.2 | 2.1, 2.2 | | 2.3 | 2.3 | Independent | ## Starting Koin with generated modules KSP generates a `.module` extension for each `@Module` class: ```kotlin import org.koin.ksp.generated.* @Single class MyComponent @Module @ComponentScan class MyModule fun main() { startKoin { modules(MyModule().module) } } ``` ## Compile-time check The KSP processor has its own configuration check, turned on with a KSP argument: ```kotlin // build.gradle.kts ksp { arg("KOIN_CONFIG_CHECK", "true") } ``` The Compiler Plugin replaces it with checks of the full graph and of every `get()` call site. See [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety). ## Kotlin Multiplatform KSP needs one configuration per target: ```kotlin // shared/build.gradle.kts plugins { id("com.google.devtools.ksp") } kotlin { sourceSets { commonMain.dependencies { implementation("io.insert-koin:koin-core:$koin_version") implementation("io.insert-koin:koin-annotations:$koin_ksp_version") } } } dependencies { add("kspAndroid", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version") add("kspIosX64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version") add("kspIosArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version") add("kspIosSimulatorArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version") } ``` With the Compiler Plugin, you apply the plugin once and add `koin-annotations` to `commonMain`. ## Moving to the Compiler Plugin The move keeps your annotated classes as they are. You remove KSP and `koin-ksp-compiler`, apply the Compiler Plugin, delete the generated sources, and replace `modules(MyModule().module)` with `startKoin()`. The step-by-step guide is [Migrating from KSP to the Compiler Plugin](/docs/migration/from-ksp-to-compiler-plugin). If you get stuck, ask on the [Kotlin Slack #koin channel](https://kotlinlang.slack.com/messages/koin/) or open an issue on [InsertKoinIO/koin-annotations](https://github.com/InsertKoinIO/koin-annotations). ## Related - [Migrating from KSP](/docs/migration/from-ksp-to-compiler-plugin): step-by-step migration. - [Compiler Plugin Setup](/docs/setup/compiler-plugin): install the replacement. - [Choosing your style](/docs/intro/choosing-your-style): annotations and the other styles. - [Annotations Reference](/docs/reference/koin-annotations/annotations-inventory): every annotation. --- # Kotlin Source: https://insert-koin.io/docs/quickstart/kotlin In this tutorial you build a Kotlin console app that loads a list of users and prints a greeting. You learn how to declare a Koin module, bind implementations to interfaces, and start Koin. It takes about 10 minutes and needs a JDK 17 and Gradle. This tutorial uses the Compiler Plugin DSL. For the same app with annotations, see [Kotlin & Annotations](/docs/quickstart/kotlin-annotations). To compare the styles, see [Choosing your style](/docs/intro/choosing-your-style). ## Get the code The full sample is in [koin-getting-started/kotlin](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kotlin). Clone the repository and run it from the `kotlin` folder: ```bash ./gradlew run ``` ## Gradle setup The sample applies the Koin Compiler Plugin and adds `koin-core`. Versions live in a version catalog: ```toml # gradle/libs.versions.toml [versions] kotlin = "" koin = "" koin-plugin = "" [libraries] koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } ``` ```kotlin // app/build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.koin.compiler) application } dependencies { implementation(libs.koin.core) testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit4) } ``` The Compiler Plugin needs Kotlin 2.3.20 or later. For current versions and the BOM, see [Gradle setup](/docs/setup/gradle). For plugin options, see [Compiler Plugin setup](/docs/setup/compiler-plugin). ## The application The app chains three components. `UserApplication` asks `UserService` for a user, and `UserService` reads from `UserRepository`: ``` User -> UserRepository -> UserService -> UserApplication ``` ## Let's write the user data Start with the data class and a default list of users: ```kotlin data class User(val name: String, val email: String) val DEFAULT_USER = User("Alice", "alice@example.com") val DEFAULT_USERS = listOf( DEFAULT_USER, User("Bob", "bob@example.com"), User("Charlie", "charlie@example.com") ) ``` These users are the data that the repository stores. ## Let's write the repository The repository keeps users in memory and finds one by name: ```kotlin interface UserRepository { fun findUserOrNull(name: String): User? fun addUsers(users: List) } class UserRepositoryImpl : UserRepository { private val _users = arrayListOf() override fun findUserOrNull(name: String): User? { return _users.firstOrNull { it.name == name } } override fun addUsers(users: List) { _users.addAll(users) } } ``` `UserRepositoryImpl` has no dependency, so Koin can create it with no extra information. ## Let's declare the Koin module A module is where you declare the components Koin creates (see [Core Concepts](/docs/intro/core-concepts)). Declare `UserRepositoryImpl` as a singleton, available as `UserRepository`: ```kotlin import org.koin.dsl.bind import org.koin.dsl.module import org.koin.plugin.module.dsl.single val appModule = module { single() bind UserRepository::class } ``` Any component that asks for a `UserRepository` now gets the same `UserRepositoryImpl` instance. `single` and `bind` are described in [Definitions](/docs/reference/koin-core/definitions). ## Let's write the service `UserService` loads the users and prepares the greeting: ```kotlin interface UserService { fun getUserOrNull(name: String = DEFAULT_USER.name): User? fun loadUsers() fun prepareHelloMessage(user: User?): String } class UserServiceImpl( private val userRepository: UserRepository ) : UserService { override fun getUserOrNull(name: String): User? = userRepository.findUserOrNull(name) override fun loadUsers() { userRepository.addUsers(DEFAULT_USERS) } override fun prepareHelloMessage(user: User?): String { return user?.let { "Hello '${user.name}' (${user.email})!" } ?: "User not found" } } ``` Add it to the module: ```kotlin val appModule = module { single() bind UserRepository::class single() bind UserService::class } ``` `UserServiceImpl` takes a `UserRepository` in its constructor. The Compiler Plugin reads that constructor and passes the `UserRepositoryImpl` instance for you. ## Let's write the application class `UserApplication` receives `UserService` through its constructor, loads the users and prints the greeting: ```kotlin class UserApplication( private val userService: UserService ) { init { userService.loadUsers() } fun sayHello(name: String) { val user = userService.getUserOrNull(name) val message = userService.prepareHelloMessage(user) println(message) } } ``` Declare it in the module too: ```kotlin val appModule = module { single() single() bind UserRepository::class single() bind UserService::class } ``` All three components are now in the module. The plugin checks at build time that each constructor parameter has a definition. ## Let's start Koin Start Koin in `main()` with your module, then get `UserApplication` from the container: ```kotlin import org.koin.core.context.startKoin import org.koin.mp.KoinPlatform fun main() { startKoin { modules(appModule) } val userApplication = KoinPlatform.getKoin().get() userApplication.sayHello("Alice") } ``` Run `./gradlew run` and the app prints `Hello 'Alice' (alice@example.com)!`. `startKoin` and its options are covered in [Starting Koin](/docs/reference/koin-core/starting-koin). ## Next steps - [Core Concepts](/docs/intro/core-concepts): the mental model behind modules, definitions and injection. - [Definitions](/docs/reference/koin-core/definitions): every definition type and binding option. - [JUnit Tests](/docs/quickstart/junit-test): test this same app with Koin Test. - [Compile-Time Safety](/docs/reference/koin-compiler/compile-safety): what the Compiler Plugin checks in your graph. - [Tooling](/docs/tooling): IDE plugin and monitoring tools for Koin. --- # Kotlin & Annotations Source: https://insert-koin.io/docs/quickstart/kotlin-annotations In this tutorial you build a Kotlin console app that loads a list of users and prints a greeting. You learn how to annotate classes, scan them into a module, and start Koin from a `@KoinApplication` object. It takes about 10 minutes and needs a JDK 17 and Gradle. This tutorial uses annotations. For the same app with the Compiler Plugin DSL, see [Kotlin](/docs/quickstart/kotlin). To compare the styles, see [Choosing your style](/docs/intro/choosing-your-style). ## Get the code The full sample is in [koin-getting-started/kotlin-annotations](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kotlin-annotations). Clone the repository and run it from the `kotlin-annotations` folder: ```bash ./gradlew run ``` ## Gradle setup The sample applies the Koin Compiler Plugin and adds `koin-core` and `koin-annotations`. Versions live in a version catalog: ```toml # gradle/libs.versions.toml [versions] kotlin = "" koin = "" koin-plugin = "" [libraries] koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" } koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } ``` ```kotlin // app/build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.koin.compiler) application } dependencies { implementation(libs.koin.core) implementation(libs.koin.annotations) testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit4) } ``` The Compiler Plugin processes the annotations and needs Kotlin 2.3.20 or later. `koin-annotations` shares the Koin version. For details, see [Gradle setup](/docs/setup/gradle) and [Compiler Plugin setup](/docs/setup/compiler-plugin). ## The application The app chains three components. `UserApplication` asks `UserService` for a user, and `UserService` reads from `UserRepository`: ``` User -> UserRepository -> UserService -> UserApplication ``` ## Let's write the user data Start with the data class and a default list of users: ```kotlin data class User(val name: String, val email: String) val DEFAULT_USER = User("Alice", "alice@example.com") val DEFAULT_USERS = listOf( DEFAULT_USER, User("Bob", "bob@example.com"), User("Charlie", "charlie@example.com") ) ``` These users are the data that the repository stores. ## Let's write the repository The repository keeps users in memory. Annotate the implementation with `@Singleton` to declare it as a singleton: ```kotlin import org.koin.core.annotation.Singleton interface UserRepository { fun findUserOrNull(name: String): User? fun addUsers(users: List) } @Singleton class UserRepositoryImpl : UserRepository { private val _users = arrayListOf() override fun findUserOrNull(name: String): User? { return _users.firstOrNull { it.name == name } } override fun addUsers(users: List) { _users.addAll(users) } } ``` Koin binds `UserRepositoryImpl` to its supertypes, so a request for `UserRepository` gets this instance. `@Singleton` comes from `org.koin.core.annotation` and is equivalent to `@Single` (see [Definitions](/docs/reference/koin-core/definitions)). ## Let's write the service `UserService` loads the users and prepares the greeting. It is a `@Singleton` too: ```kotlin interface UserService { fun getUserOrNull(name: String = DEFAULT_USER.name): User? fun loadUsers() fun prepareHelloMessage(user: User?): String } @Singleton class UserServiceImpl( private val userRepository: UserRepository ) : UserService { override fun getUserOrNull(name: String): User? = userRepository.findUserOrNull(name) override fun loadUsers() { userRepository.addUsers(DEFAULT_USERS) } override fun prepareHelloMessage(user: User?): String { return user?.let { "Hello '${user.name}' (${user.email})!" } ?: "User not found" } } ``` The Compiler Plugin reads the constructor and passes the `UserRepository` instance for you. ## Let's write the application class `UserApplication` receives `UserService` through its constructor, loads the users and prints the greeting: ```kotlin @Singleton class UserApplication( private val userService: UserService ) { init { userService.loadUsers() } fun sayHello(name: String) { val user = userService.getUserOrNull(name) val message = userService.prepareHelloMessage(user) println(message) } } ``` All three components are now annotated. Next, gather them in a module. ## Let's declare the Koin module A module groups definitions (see [Core Concepts](/docs/intro/core-concepts)). Declare a module class that scans the sample package: ```kotlin import org.koin.core.annotation.ComponentScan import org.koin.core.annotation.Configuration import org.koin.core.annotation.Module @Module @ComponentScan("org.koin.sample") @Configuration class AppModule ``` `@ComponentScan` registers every annotated class in `org.koin.sample` and its subpackages. `@Configuration` makes the module discoverable by a `@KoinApplication` entry point. Both are described in [Modules](/docs/reference/koin-core/modules). ## Let's start Koin Declare a `@KoinApplication` object and start Koin with the typed `startKoin()`: ```kotlin import org.koin.core.annotation.KoinApplication import org.koin.mp.KoinPlatform import org.koin.plugin.module.dsl.startKoin @KoinApplication object KoinUserApplication fun main() { startKoin() val userApplication = KoinPlatform.getKoin().get() userApplication.sayHello("Alice") } ``` `startKoin()` loads every `@Configuration` module, so you don't call `modules()`. The plugin validates the full graph at build time, and `./gradlew run` prints `Hello 'Alice' (alice@example.com)!`. See [Starting Koin](/docs/reference/koin-core/starting-koin) for the other options. ## Next steps - [Core Concepts](/docs/intro/core-concepts): the mental model behind modules, definitions and injection. - [Modules](/docs/reference/koin-core/modules): `@Module`, `@ComponentScan`, `@Configuration` and module includes. - [Annotations Reference](/docs/reference/koin-annotations/annotations-inventory): every annotation and its parameters. - [Testing](/docs/reference/koin-test/testing): write tests with Koin Test. - [Tooling](/docs/tooling): IDE plugin and monitoring tools for Koin. --- # Android Source: https://insert-koin.io/docs/quickstart/android In this tutorial you build an Android app that greets a user picked from a list. You learn how to declare a Koin module, inject a presenter in an Activity, and start Koin from your `Application` class. It takes about 10 minutes and needs Android Studio. This tutorial uses the Compiler Plugin DSL. For the same app with annotations, see [Android & Annotations](/docs/quickstart/android-annotations). To compare the styles, see [Choosing your style](/docs/intro/choosing-your-style). The [Android ViewModel](/docs/quickstart/android-viewmodel) tutorial builds the same app with a ViewModel instead of a presenter. ## Get the code The full sample is in [koin-getting-started/android](https://github.com/InsertKoinIO/koin-getting-started/tree/main/android). Clone the repository and open the `android` folder in Android Studio. ## Gradle setup The sample applies the Koin Compiler Plugin and adds `koin-android`. Versions live in a version catalog: ```toml # gradle/libs.versions.toml [versions] # Kotlin, Android Gradle Plugin and AndroidX entries omitted koin = "" koin-plugin = "" [libraries] koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } koin-android-test = { module = "io.insert-koin:koin-android-test", version.ref = "koin" } [plugins] koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } ``` ```kotlin // app/build.gradle.kts plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.koin.compiler) } dependencies { implementation(libs.android.appcompat) implementation(libs.koin.android) testImplementation(libs.koin.test.junit4) testImplementation(libs.koin.android.test) } ``` The Compiler Plugin needs Kotlin 2.3.20 or later. For current versions and the BOM, see [Gradle setup](/docs/setup/gradle). For plugin options, see [Compiler Plugin setup](/docs/setup/compiler-plugin). ## The application The Activity asks a presenter for a greeting. The presenter uses `UserService`, which reads from `UserRepository`: ``` User -> UserRepository -> UserService -> UserPresenter -> MainActivity ``` ## Let's write the user data Start with the data class and a default list of users: ```kotlin data class User(val name: String, val email: String) val DEFAULT_USER = User("Alice", "alice@example.com") val DEFAULT_USERS = listOf( DEFAULT_USER, User("Bob", "bob@example.com"), User("Charlie", "charlie@example.com") ) ``` These users are the data that the repository stores. ## Let's write the repository The repository keeps users in memory and finds one by name: ```kotlin interface UserRepository { fun findUserOrNull(name: String): User? fun addUsers(users: List) } class UserRepositoryImpl : UserRepository { private val _users = arrayListOf() override fun findUserOrNull(name: String): User? { return _users.firstOrNull { it.name == name } } override fun addUsers(users: List) { _users.addAll(users) } } ``` `UserRepositoryImpl` has no dependency, so Koin can create it with no extra information. ## Let's write the service `UserService` loads the users when it is created and prepares the greeting: ```kotlin interface UserService { fun getUserOrNull(name: String = DEFAULT_USER.name): User? fun loadUsers() fun prepareHelloMessage(user: User?): String } class UserServiceImpl( private val userRepository: UserRepository ) : UserService { init { loadUsers() } override fun getUserOrNull(name: String): User? = userRepository.findUserOrNull(name) override fun loadUsers() { userRepository.addUsers(DEFAULT_USERS) } override fun prepareHelloMessage(user: User?): String { return user?.let { "Hello '${user.name}' (${user.email})!" } ?: "User not found" } } ``` `UserServiceImpl` depends on `UserRepository`. Koin passes it through the constructor. ## Let's declare the Koin module A module is where you declare the components Koin creates (see [Core Concepts](/docs/intro/core-concepts)). Declare both components as singletons, bound to their interfaces: ```kotlin import org.koin.dsl.bind import org.koin.dsl.module import org.koin.plugin.module.dsl.single val appModule = module { single() bind UserRepository::class single() bind UserService::class } ``` Any component that asks for `UserService` now gets the same `UserServiceImpl` instance. `single` and `bind` are described in [Definitions](/docs/reference/koin-core/definitions). ## Let's write the presenter The presenter turns a name into a greeting: ```kotlin class UserPresenter( private val userService: UserService ) { fun sayHello(name: String): String { val user = userService.getUserOrNull(name) val message = userService.prepareHelloMessage(user) return "[UserPresenter] $message" } } ``` Declare it with `factory`, so each request creates a new instance and Koin keeps no reference to it: ```kotlin import org.koin.plugin.module.dsl.factory val appModule = module { single() bind UserRepository::class single() bind UserService::class factory() } ``` A `factory` presenter cannot outlive the Activity that uses it, which avoids leaking the Activity. ## Let's inject the presenter in the Activity Use the `by inject()` delegate to get the presenter in `MainActivity`: ```kotlin import org.koin.android.ext.android.inject class MainActivity : AppCompatActivity() { private val presenter: UserPresenter by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_simple) val nameInput = findViewById(R.id.nameInput) val sayHelloButton = findViewById