Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.

Build Magnet Kotlin version badge Maven Central License

🧲 Magnet

Magnet is a concise, scope tree based Dependency Injection (DI) library designed for highly modular Android applications. It consists of two parts: an annotation processor (Kotlin) and a reflection free runtime library (Java + Kotlin).


Magnet defines and opetates on two core concepts: Scopes and Instances.

Scope is a container for instances. Scopes can be combined into a hierarchical tree by referencing parent scopes. The most top scope of the tree hierarchy, which has no parent scope, is called the root scope.

Instance is a concrete occurance of an injected type. Instances can be allocated in scopes (scoped instances) or outside of scopes (unscoped instances).

The Dependency Rule

Scopes depend on each other using the strong dependency rule - scope dependency can only point torwards its parent scope. The dependency direction between two scopes enforces the direction of dependencies between instances allocated in those scopes. Instances allocated in a parent scope can know nothing about instances allocated in its child scopes. This simple design rule helps preventing memory leaks and allows safe disposal of child scopes and garbage collecting instances allocated there.

Getting Started

In the example below we will compose a very naive MediaPlayer which loads media using a MediaLoader and then plays the media.

fun main() {
   val rootScope = MagnetScope.createRootScope()
   val playerScope = rootScope.createSubscope {
   // mark 1
   val mediaPlayer = playerScope.getSingle<MediaPlayer>()
   // mark 2
   // mark 3

// MediaPlayer.kt
interface MediaPlayer {
   fun playWhenReady()

@Instance(type = MediaPlayer::class, disposer = "dispose")
internal class DefaultMediaPlayer(
   private val assetId: Uri,
   private val mediaLoader: MediaLoader
) : MediaPlayer {
   override fun playWhenReady() { ... }
   fun dispose() { ... }

// MediaLoader.kt
interface MediaLoader {
   fun load(mediaUri: Uri): Single<Media>

@Instance(type = MediaLoader::class)
internal class DefaultMediaLoader() : MediaLoader {
   override fun load(mediaUri: Uri): Single<Media> { ... }

The diagram below shows how Magnet manages the scope hierarchy when different marks of the main function are reached.

At Mark 1, two scopes are created and the Uri instance gets bound into the playerScope.

At Mark 2, mediaPlayer and mediaLoader instances get allocated in respective scopes. mediaPlayer is allocated in the playerScope because one of its dependencies, the Uri, is located in playerScope. Magnet cannot move mediaPlayer up to the rootScope because this would break the dependency rule described above. mediaLoader has no dependencies, that's why it is allocated in the rootScope. This instance allocation logic is specific to Magnet DI and is called auto-scoping. See developer documentation for more detail.

At Mark 3, the playerScope gets disposed and all its instances are garbage collected.

For more information refer to Magnet documentation.


  1. Developer Guide
  2. Dependency auto-scoping
  3. Scope Inspection
  4. How to Inject Android ViewModels
  5. Blog: Magnet - an alternative to Dagger
  6. Co2Monitor sample app
  7. Another sample app


  • Minimalistic API
  • Auto-scoping of instances
  • Hierarchical, disposable scopes
  • Kotlin friendly annotation
  • Injection into Kotlin constructors with default arguments
  • Injection from binary libraries
  • Dependency inversion
  • No direct references to Magnet generated code
  • No reflection for injection, apt generated factory classes
  • Extensible - some magnetx extensions are available
  • Customizable - custom factories and instance selectors

Why Magnet?

Magnet was crafted with simplicity and development speed in mind. It lets developers spend less time on DI configuration and do more other stuff, also more mistakes when used inattentively. Magnet motivates you writing highly modular apps because it makes DI so simple. It can even inject instances from the libraries added in build scripts without necessity to adapt source code. Magnet could be interesting for those, who needs an easy to configure and simple DI with more runtime control.

Why not Magnet?

If compile time consistency validation is your highest priority, I recommend using awesome Dagger2 instead. You will spend slightly more time on DI configuration but Dagger2 lets you keep it highly consistent and error prone (in most cases) very early in the development cycle - at compile time.

Peace ✌️ and have fun.



repositories {
dependencies {
   api 'de.halfbit:magnet-kotlin:<version>'
   kapt 'de.halfbit:magnet-processor:<version>'


repositories {
dependencies {
   api 'de.halfbit:magnet:<version>'
   annotationProcessor 'de.halfbit:magnet-processor:<version>'


Kotlin Version Magnet Version
1.7.x 3.7 (snapshot)
1.6.x 3.6
1.5.x 3.5
1.4.x 3.4
1.3.x 3.4

Proguard & R8

-keep class magnet.internal.MagnetIndexer { *; }

Build from Sources

  1. Set JAVA_HOME variable to JDK 11.
  2. Import project into Android Studio.
  3. Set Gradle → Gradle Settings... → Gradle JDK to JDK 11.
  4. To build the project run ./gradlew build
  5. To release the project run ./gradlew publish

Maven repository configurations

Repository Configuration
Central mavenCentral()
Snapshot maven { url = "" }
Local mavenLocal()


Copyright 2018-2022 Sergej Shafarenka,

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.


Dependency injection library for modular Android applications








No packages published