{"id":23424571,"url":"https://github.com/Ivy-Apps/di","last_synced_at":"2025-08-25T14:31:58.792Z","repository":{"id":253972769,"uuid":"845095104","full_name":"Ivy-Apps/di","owner":"Ivy-Apps","description":"A simple DI library for Kotlin Multiplatform apps.","archived":false,"fork":false,"pushed_at":"2025-08-17T09:24:41.000Z","size":351,"stargazers_count":37,"open_issues_count":1,"forks_count":7,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-17T11:29:14.963Z","etag":null,"topics":["dependency-injection","di-container","kmp","kmp-library","kotlin","kotlin-js","kotlin-jvm","kotlin-library","kotlin-multiplatform","kotlin-native","lightweight","service-locator"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ivy-Apps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-08-20T15:13:13.000Z","updated_at":"2025-08-17T09:24:44.000Z","dependencies_parsed_at":"2024-08-26T18:38:55.122Z","dependency_job_id":"abdf99a8-97a0-45d8-a262-48cfd6870d3a","html_url":"https://github.com/Ivy-Apps/di","commit_stats":null,"previous_names":["ivy-apps/di"],"tags_count":2,"template":false,"template_full_name":"Kotlin/multiplatform-library-template","purl":"pkg:github/Ivy-Apps/di","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ivy-Apps%2Fdi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ivy-Apps%2Fdi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ivy-Apps%2Fdi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ivy-Apps%2Fdi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ivy-Apps","download_url":"https://codeload.github.com/Ivy-Apps/di/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ivy-Apps%2Fdi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272079997,"owners_count":24869816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","di-container","kmp","kmp-library","kotlin","kotlin-js","kotlin-jvm","kotlin-library","kotlin-multiplatform","kotlin-native","lightweight","service-locator"],"created_at":"2024-12-23T05:00:26.412Z","updated_at":"2025-08-25T14:31:58.783Z","avatar_url":"https://github.com/Ivy-Apps.png","language":"Kotlin","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"\u003e [!WARNING]\n\u003e\n\u003e **Depreciation Notice**\n\u003e\n\u003e This library is deprecated and no longer maintained. If you're targeting native Android we recommend using [Hitl](https://developer.android.com/training/dependency-injection/hilt-android), for KMP - [Metro](https://github.com/ZacSweers/metro). If you're looking for a similar API, check out [Koin](https://github.com/InsertKoinIO/koin).\n\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![Maven Central Version](https://img.shields.io/maven-central/v/com.ivy-apps/di?color=5C3DF5)](https://central.sonatype.com/artifact/com.ivy-apps/di)\n[![CI](https://github.com/Ivy-Apps/di/actions/workflows/ci.yml/badge.svg)](https://github.com/Ivy-Apps/di/actions/workflows/ci.yml)\n[![Publish](https://github.com/Ivy-Apps/di/actions/workflows/publish.yml/badge.svg)](https://github.com/Ivy-Apps/di/actions/workflows/publish.yml)\n\n[![Kotlin Multiplatform](https://img.shields.io/badge/Kotlin-Multiplatform-blue?logo=kotlin\u0026style=flat)](https://central.sonatype.com/artifact/com.ivy-apps/di)\n[![Platforms](https://img.shields.io/badge/platforms-JVM%20|%20Android%20|%20iOS%20|%20Native%20|%20JS%20|%20WASM-brightgreen)](https://central.sonatype.com/artifact/com.ivy-apps/di)\n\n# Ivy DI ⚡\n\nA simple and lightweight runtime Dependency Injection (DI) container for Kotlin Multiplatform.\nIvy DI is a small dependency injection library with an intuitive API and limited features.\n\nIn a nutshell, you first register dependency factory functions in the container `Di.register { SomeClass() }` and then\nget instances via `Di.get\u003cSomeClass\u003e()`. It also supports auto-wiring via `autoWire(::SomeClass)` that does it\nautomatically for you.\n\n```kotlin\ninterface ArticlesDataSource\nclass RemoteArticlesDataSource(\n  val client: HttpClient,\n  val baseUrl: BaseUrlProvider\n) : ArticlesDataSource\nclass ArticlesRepository(val source: ArticlesDataSource)\n\nobject AppModule : Di.Module {\n  override fun init() = Di.appScope {\n    register { BaseUrlProvider(\"https://ivy-apps.com\") }\n    singleton { HttpClient(CIO) }\n    autoWire(::RemoteArticlesDataSource)\n    bind\u003cArticlesDataSource, RemoteArticlesDataSource\u003e()\n    autoWireSingleton(::ArticlesRepository)\n  }\n}\n\nfun main() {\n  Di.init(AppModule) // activates the AppModule (i.e. executes its code)\n  val repo = Di.get\u003cArticlesRepository\u003e() // ArticlesRepository instance created\n}\n```\n\n### Features\n\n- [Lightweight \u0026 Efficient](di/src/commonMain/kotlin/ivy/di/DiContainer.kt)\n- [One-line setup](https://github.com/Ivy-Apps/di?tab=readme-ov-file#0-setup)\n- [Simple and easy to use](https://github.com/Ivy-Apps/di?tab=readme-ov-file#1-register-a-dependency)\n- [Auto-wiring](https://github.com/Ivy-Apps/di?tab=readme-ov-file#4-auto-wiring)\n- [Singletons](https://github.com/Ivy-Apps/di?tab=readme-ov-file#3-singleton-dependencies)\n- [Bindings](https://github.com/Ivy-Apps/di?tab=readme-ov-file#5-bindings)\n- [Qualifiers](https://github.com/Ivy-Apps/di?tab=readme-ov-file#6-named-dependencies-qualifiers)\n- [Modules](https://github.com/Ivy-Apps/di?tab=readme-ov-file#7-modules)\n- [Scopes](https://github.com/Ivy-Apps/di?tab=readme-ov-file#1-scopes)\n- [Lazy intitliazation](https://github.com/Ivy-Apps/di?tab=readme-ov-file#3-lazy-initialization)\n- [KDoc on every method](di/src/commonMain/kotlin/ivy/di/DiContainer.kt)\n\n\u003e [!WARNING]\n\u003e Before deciding whether to use it, make sure to check the [Limitations](https://github.com/Ivy-Apps/di?tab=readme-ov-file#%EF%B8%8F-limitations).\n\n## Benchmarks\n\nBased on [this Benchmark test](https://github.com/Ivy-Apps/di/blob/c35b864f0a8bc94b87f60ebbc58c1eed837d7a09/benchmark/src/main/kotlin/ivy/di/benchmark/DiBenchmark.kt) from [this CI run](https://github.com/Ivy-Apps/di/actions/runs/12339164458/job/34435040689) Ivy DI performs better than [Koin](https://github.com/InsertKoinIO/koin)\nand [Kodein](https://github.com/kosi-libs/Kodein) on the \"medium\" and \"complex\" DI graphs test cases.\n\n| **Library** | **Startup**   | **Small graph**     | **Medium graph**     | **Complex graph**     |\n|-------------|---------------|--------------------|---------------------|----------------------|\n| **Ivy DI**  | ≈ 10⁻⁵ ms     | 0.058 ± 0.001 ms   | 0.204 ± 0.001 ms    | 1.079 ± 0.004 ms     |\n| **Koin**    | ≈ 10⁻³ ms     | 0.061 ± 0.001 ms   | 0.554 ± 0.003 ms    | 3.522 ± 0.018 ms     |\n| **Kodein**  | ≈ 10⁻⁴ ms     | 0.051 ± 0.001 ms   | 0.436 ± 0.002 ms    | 3.725 ± 0.041 ms     |\n\nWe encourage developers to [review the benchmark setup](https://github.com/Ivy-Apps/di/blob/c35b864f0a8bc94b87f60ebbc58c1eed837d7a09/benchmark/src/main/kotlin/ivy/di/benchmark/DiBenchmark.kt) and propose improvements. PRs that make the benchmarks fairer and more comprehensive are more than welcome!\n\n## Usage\n\n### 0. Setup\n\nYou can find Ivy DI in [our Ivy DI Maven Central repository](https://central.sonatype.com/artifact/com.ivy-apps/di).\n\nReplace `?.?.?`\nwith the numbers from: [![Maven Central Version](https://img.shields.io/maven-central/v/com.ivy-apps/di?color=5C3DF5)](https://central.sonatype.com/artifact/com.ivy-apps/di)\n\n**Gradle (Kotlin)**\n\n```gradle\nimplementation(\"com.ivy-apps:di:?.?.?\")\n```\n\nor\n\n**Version Catalog**\n\n```toml\n[libraries]\nivyApps-di = { module = \"com.ivy-apps:di\", version = \"?.?.?\" }\n```\n\n```gradle\nimplementation(libs.ivyApps.di)\n```\n\nThat's all you need! Now let's start using Ivy DI ✨️\n\n### 1. Register a dependency\n\n```kotlin\nclass A\nclass B(val a: A)\n\nDi.appScope {\n  register { A() }\n  register { B(a = Di.get()) }\n}\n```\n\nInstances of `A` and `B` won't be created until the dependencies are requested in the code (lazy creation).\n\n### 2. Get dependency instance\n\n```kotlin\n// instances of B and its dependencies will be created\nDi.get\u003cB\u003e() // instance 1 of B\nDi.get\u003cB\u003e() // instance 2 of B\n```\n\nEach call to `Di.get()` creates a **new** instance for non-singleton dependencies.\n\n### 3. Singleton dependencies\n\n```kotlin\nclass Counter(var x: Int = 0) {\n  init {\n    print(\"Counter created. \")\n  }\n}\n\nDi.appScope {\n  singleton {\n    Counter() // instance won't be created here \n  }\n}\n\nprintln(Di.get\u003cCounter\u003e().x) // Counter created. 0\nDi.get\u003cCounter\u003e().x++\nprintln(Di.get\u003cCounter\u003e().x) // 1\n```\n\nSingleton dependencies will have only one **single instance**\nthat will be created on the first `Di.get()` call.\n\nTo clear singleton instance and free memory use `Di.clear(scope)`.\nFor example, to clear the counter - `Di.clear(AppScope)`.\n\n### 4. Auto-wiring\n\n```kotlin\nclass A\nclass B(val a: A)\nclass C(val a: A, val b: B)\nclass D(val a: A, val b: B, val c: C)\n\nDi.appScope {\n  autoWire(::A)\n  // equivalent to register { A() }\n  autoWireSingleton(::B) // for singletons\n  // equivalent to singleton { B(a = Di.get()) }\n  autoWire(::C)\n  // equivalent to register { C(Di.get(), Di.get()) }\n  autoWire(::D)\n  // equivalent to register { D(Di.get(), Di.get(), Di.get()) }\n}\nDi.get\u003cD\u003e() // instance of D created\n```\n\nTo avoid repetitive code like `register { D(Di.get(), Di.get(), Di.get()) }`\nit's recommended to use auto-wiring.\n\n\u003e [!TIP]\n\u003e **Always auto-wire**\n\u003e \n\u003e When possible always use auto-wiring and fallback to\n\u003e register/singleton only when absolutely necessary.\n\u003e This way you won't have to modify the registered factories\n\u003e when you change the constructor of the dependency that's being injected.\n\n### 5. Bindings\n\n```kotlin\ninterface Platform\nclass AndroidPlatform : Platform\n\nDi.appScope {\n  autoWire(::AndroidPlatform)\n  bind\u003cPlatform, AndroidPlatform\u003e()\n  // equivalent to:\n  // register\u003cPlatform\u003e { AndroidPlatform() }\n}\nDi.get\u003cPlatform\u003e() // AndroidPlatform instance\n```\n\nTo bind a specific implementation to an interface (or an abstract class) use `bind\u003cInterface, Impl\u003e()`. Note: `Impl`\nmust be registered in the dependency graph.\n\n### 6. Named dependencies (qualifiers)\n\n```kotlin\ninterface TimeFormatter\nclass H24TimeFormatter : TimeFormatter\nclass AmPmTimeFormatter : TimeFormatter\n\nDi.appScope {\n  autoWire(::H24TimeFormatter)\n  autoWire(::AmPmTimeFormatter)\n  bind\u003cTimeFormatter, H24TimeFormatter\u003e() // default\n  bind\u003cTimeFormatter, AmPmTimeFormatter\u003e(named = \"am-pm\")\n}\n\nDi.get\u003cTimeFormatter\u003e() // H24TimeFormatter\nDi.get\u003cTimeFormatter\u003e(named = \"am-pm\") // AmPmTimeFormatter\n```\n\nSometimes we need to have different instances of the same type.\nTo achieve this in Ivy DI, we can set qualifiers using `named = \"something\"` (you're not limited only to strings because\n`named: Any`).\n\n\u003e [!IMPORTANT]\n\u003e Your \"named\" qualifiers must support equality checks (hashCode + equals).\n\n### 7. Modules\n\n```kotlin\nobject DataModule : Di.Module {\n  override fun init() = Di.appScope {\n    singleton { HttpClient(CIO) }\n    register { Json() }\n    autoWire(::LoginService)\n    autoWireSingleton(::AnalyticsService)\n  }\n}\n\nobject DomainModel : Di.Module {\n  override fun init() = Di.app {\n    autoWire(::LoginUseCaseImpl)\n    bind\u003cLoginUseCase, LoginUseCaseImpl\u003e()\n    autoWireSingleton(::SessionManager)\n  }\n}\n\nDi.init(\n  // Registers the following modules in the DI container\n  DataModule,\n  DomainModule\n)\nDi.get\u003cLoginUseCase\u003e() // instance of LoginUseCaseImpl created\n```\n\nTo encapsulate and re-use DI logic you can create `Di.Module`.\nTo activate the DI module you need to call `Di.init(MyModule)`.\n\n\u003e [!TIP]\n\u003e On each  architecture layer or feature layer, you can create a `di` package with DI modules inside. Then in your\n\u003e application root or feature entrypoint,\n\u003e call `Di.init(ModuleA, ModuleB, ...)` with all modules that you need to use.\n\n## Advanced Usage\n\n### 1. Scopes\n\nIvy DI supports grouping your dependencies into scopes. This way you can manage their lifecycle\nand free resources when they are no longer needed. **AppScope** and **FeatureScope**\nare built-in, but you can easily define your own scopes using `Di.newScope(\"my-scope\")`.\n\n```kotlin\ndata class UserInfo(val id: String, val name: String)\n\nval UserScope = Di.newScope(\"user\")\nfun Di.userScope(block: Di.Scope.() -\u003e Unit) = Di.inScope(UserScope, block) // helper function (optional)\n\nsuspend fun login() {\n  val userInfo = loginInternally() // UserInfo(\"1\", \"John\")\n  Di.userScope {\n    // Register dependencies for the lifecycle of a user\n    singleton { userInfo }\n  }\n}\n\n// Note: This function must be called only for logged-in users,\n// otherwise Di.get() will throw an exception.\nsuspend fun dashboard() {\n  // Use user related dependencies\n  val userInfo = Di.get\u003cUserInfo\u003e()\n  println(\"Hello, ${userInfo.name}\") // \"Hello, John\"\n}\n\nsuspend fun logout() {\n  logoutInternally()\n  // Frees all dependencies in UserScope\n  Di.clear(UserScope) // UserInfo(\"1\", \"John\") gets cleared\n}\n```\n\nScopes are also extremely useful for defining multiple dependencies of the same type\nand picking the most appropriate one based on the scope using **affinity**.\n\n```kotlin\ndata class Screen(val name: String)\nDi.appScope {\n  register\u003cString\u003e { \"Hello from app!\" }\n  autoWire(::Screen)\n}\nDi.featureScope {\n  register\u003cString\u003e { \"Hello from feature!\" }\n  autoWire(::Screen)\n}\n\nDi.get\u003cString\u003e(affinity = AppScope) // \"Hello from app!\"\nDi.get\u003cScreen\u003e(affinity = AppScope) // Screen(name=\"Hello from app!\")\nDi.get\u003cString\u003e(affinity = FeatureScope) // \"Hello from feature!\"\nDi.get\u003cScreen\u003e(affinity = FeatureScope) // Screen(name=\"Hello from feature!\")\n```\n\n\u003e [!NOTE]\n\u003e Auto-wiring automatically sets the affinity to the scope from which it's called.\n\n### 2. Multi-bindings 🚧\n\nCurrently not supported, investigating this use-case and whether we can support it nicely.\n\n\u003e [!WARNING]\n\u003e So far, we haven't found a nice and efficient solution.\n\u003e Currently, multi-bindings are not on the roadmap. The main blocker is the limited KClass\u003c*\u003e support for generics.\n\n### 3. Lazy initialization\n\nBy default, all instances in Ivy DI are lazily initialized only after `Di.get()` is called.\nHowever, there are cases where you might want to postpone the initialization even further.\nYou can do that by wrapping your dependency in `Lazy\u003cT\u003e` and using `Di.getLazy\u003cT\u003e()` instead.\n\n```kotlin\nclass ArticlesDataSource(val client: Lazy\u003cHttpClient\u003e) {\n  suspend fun fetchLatest(): List\u003cArticle\u003e = client.value.get(\"url\") // .value gets an instance of the HttpClient\n}\nclass ArticlesRepository(val source: ArticlesDataSource) {\n  suspend fun fetchLatest(): List\u003cArticle\u003e = source.fetchLatest()\n}\n\nDi.appScope {\n  singleton { HttpClient(CIO) }\n  register {\n    // autoWire won't work because you need to explicitly call Di.getLazy() instead of Di.get()\n    ArticlesDataSource(Di.getLazy())\n  }\n  autoWire(::ArticlesRepository)\n}\nval repo = Di.get\u003cArticlesRepository\u003e() // HttpClient instance not created\nrepo.fetchLatest() // HttpClient instance created\n```\n\nThe instance of `HttpClient` will be created only after the `ArticlesDataSource#fetchLatest()` method is called.\n\n## ⚠️ Limitations\n\n### Generics aren't fully supported\n\nTo avoid performance and compatibility problems we limit reflection to the bare minimum.\nIvy DI uses only `KClass\u003c*\u003e` which unfortunately doesn't make a difference between the generic type of the class.\n\n**Problematic code:**\n\n```kotlin\nclass Container\u003cT\u003e(val value: T)\n\nDi.appScope {\n  register {\n    // perceived as Container\u003c*\u003e, information for the Int generic type is lost\n    Container\u003cInt\u003e(42)\n  }\n  register { Container\u003cString\u003e(\"hello\") } // will override the factory for Container\u003cInt\u003e\n}\n\nval intContainer = Di.get\u003cContainer\u003cInt\u003e\u003e() // Container\u003cString\u003e(\"hello\") instance created.\nintContainer.value // \"hello\" (String) even tough we requested Container\u003cInt\u003e!\nval x = intContainer.value + 1 // ClassCastException: class java.lang.String cannot be cast to class java.lang.Number\nDi.get\u003cContainer\u003cString\u003e\u003e() // Container\u003cString\u003e(\"hello\") instance created\n```\n\nThis is very weird and has some nasty implications that break type-safety.\n\nTo overcome this `KClass` limitation, the workaround is to wrap your generics in value classes.\n\n**Workaround:**\n\n```kotlin\nclass Container\u003cT\u003e(val value: T)\n\n@JvmInline\nvalue class IntContainer(val value: Container\u003cInt\u003e)\n\n@JvmInline\nvalue class StringContainer(val value: Container\u003cString\u003e)\n\nDi.appScope {\n  register { IntContainer(Container(42)) }\n  register { StringContainer(Container(\"hello\")) }\n}\n\nDi.get\u003cIntContainer\u003e().value // Container\u003cInt\u003e(42) instance created\nDi.get\u003cStringContainer\u003e().value // Container\u003cString\u003e(\"hello\") instance created\n```\n\nThe same applies for `List\u003cT\u003e`, `Set\u003cT\u003e`, `Map\u003cK, V\u003e` and any generic class.\nThe fix is to wrap it in some value class and register + inject the value class wrapper.\n\n### Thread-safety\n\nThe Ivy DI APIs aren't synchronized and thread-safety is a **responsibility of the API user**. We made this decision to\nkeep the DI container free of Java (or 3rd party) dependencies and prioritize efficiency. We recommend registering your\ndependencies on the main thread.\n\n### Maintenance\n\nThe library will be maintained as long as Ivy Apps Ltd has an interest in using it.\nGiven that Ivy DI currently has no community, the project may be abandoned in the future.\n\n\u003e **Disclaimer**\n\u003e\n\u003e _Ivy DI is provided \"as is\" under the [Apache 2.0 License](LICENSE),\nwithout warranties of any kind, including but not limited to\nfitness for a particular purpose or security.\nUse it at your own risk. The authors are not liable for\nany issues, defects, security vulnerabilities,\nor damages arising from its use.\nMaintenance, updates, and support are not guaranteed._\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=Ivy-Apps/di\u0026type=Date)](https://star-history.com/#Ivy-Apps/di\u0026Date)\n\n## Featured Projects 🚀\n\nKotlin Multiplatform projects that are using Ivy DI:\n\n### [Ivy Learn (ivylearn.app)](https://github.com/Ivy-Apps/learn)\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FIvy-Apps%2Fdi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FIvy-Apps%2Fdi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FIvy-Apps%2Fdi/lists"}