Koin — apa itu, prinsip Dependency Injection dan cara kerjanya

Penulis: IT Sectr Diterbitkan: 2026-05-04 Waktu membaca: 8 mnt

Koin adalah framework DI untuk Kotlin yang bekerja tanpa pembuatan kode, refleksi, dan anotasi. Pustaka ini menggunakan DSL untuk mendeskripsikan modul dan menginjeksi dependensi melalui container ringan dengan dukungan Android, Ktor, dan Multiplatform. Menurut dokumentasi resmi Koin, framework ini menyediakan modul, scope, dan dukungan bawaan untuk Jetpack Compose dengan boilerplate minimal.

Poin-poin utama

  • Koin — framework DI untuk Kotlin yang menggunakan DSL tanpa refleksi dan pembuatan kode.
  • Modul — pengelompokan logis registrasi dependensi melalui fungsi single dan factory.
  • single — registrasi singleton yang instansinya dibuat satu kali.
  • factory — registrasi di mana setiap permintaan membuat instansi baru.
  • Scope — mekanisme pengikatan siklus hidup dependensi ke komponen, misalnya ke Activity.

Apa itu Koin dan perbedaannya

Koin — framework DI untuk Kotlin, ditulis dalam bahasa murni tanpa menggunakan refleksi, anotasi, atau pembuatan kode. Tidak seperti Dagger Hilt yang memerlukan prosesor anotasi dan pembuatan kode pada tahap kompilasi, Koin bekerja secara eksklusif di runtime menggunakan DSL ringan untuk mendeskripsikan modul.

Ide utama Koin adalah menyediakan API sederhana untuk registrasi dan resolusi dependensi tanpa perlu mempelajari konsep rumit grafik dependensi dan pohon komponen. Pengembang menjelaskan kelas mana yang tersedia untuk container, dan Koin secara otomatis menginjeksinya melalui konstruktor atau delegasi malas by inject. Framework ini sepenuhnya kompatibel dengan Kotlin Multiplatform, memungkinkan pendekatan DI terpadu di Android, iOS, dan sisi server.

Menurut survei Kotlin Developers Community (2025), Koin digunakan di 31% proyek Android komersial, hanya kalah populer dari Hilt (47%). Alasan utama pemilihan — kesederhanaan konfigurasi dan tidak perlunya pembuatan kode, yang mempercepat pembangunan proyek.

Pilih Koin untuk proyek menengah dan besar yang mengutamakan awal pengembangan yang cepat, atau untuk solusi Kotlin Multiplatform di mana Hilt tidak tersedia karena alasan arsitektural.

Koin tidak menggunakan refleksi dan pembuatan kode — semua registrasi didasarkan pada fungsi inline dengan tipe reified yang pada tahap kompilasi mensubstitusi tipe konkret ke dalam tubuh fungsi. Ini menjadikan Koin salah satu framework DI paling ringan dalam hal ukuran APK akhir: penambahan Koin hanya meningkatkan ukuran aplikasi sebesar 100–150 KB, sedangkan Dagger Hilt menambahkan sekitar 500 KB karena kode yang dihasilkan.

Cara kerja container dan DSL Koin

Container Koin diinisialisasi melalui fungsi startKoin yang menerima lambda dengan konfigurasi. Di dalam lambda ini, modul dengan registrasi dijelaskan — blok bangunan utama logika DI.

startKoin dan modul

Fungsi startKoin membuat container global yang dapat diakses dari titik mana pun dalam aplikasi melalui GlobalContext, namun dalam proyek multi-modul disarankan menggunakan KoinApplication untuk membuat container terisolasi. Di Android, untuk inisialisasi digunakan AndroidContext yang secara otomatis terikat ke siklus hidup Application. Modul didaftarkan melalui parameter modules yang menerima daftar instansi Module.

kotlin
val networkModule = module {
    single {
        OkHttpClient()
    }
    single {
        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

startKoin {
    modules(networkModule)
}

Setiap modul berisi definisi melalui single (singleton) atau factory (instansi baru). Definisi dapat merujuk ke dependensi terdaftar lainnya melalui get(), membentuk grafik injeksi tanpa penentuan tipe secara eksplisit dan tanpa kode boilerplate.

DSL dan fungsi inline

Koin secara aktif menggunakan fungsi inline dengan parameter reified untuk menyimpulkan tipe dari konteks. Ini memungkinkan penulisan registrasi tanpa menyebutkan kelas secara eksplisit: single { MyService() } secara otomatis menentukan tipe berdasarkan nilai kembalian lambda.

Tidak seperti Dagger, Koin tidak memeriksa grafik dependensi pada tahap kompilasi — semua kesalahan terdeteksi di runtime saat pertama kali mengakses dependensi yang belum terselesaikan. Ini adalah kompromi yang secara signifikan menyederhanakan kode dan mempercepat pembangunan, tetapi memerlukan cakupan tes pada konfigurasi DI. Banyak tim memilih Koin justru karena kecepatan pengembangan dan kesederhanaan, meskipun tidak ada pemeriksaan waktu kompilasi.

Di versi Koin 3.5, pemeriksaan eksperimental grafik pada tahap kompilasi muncul melalui plugin Koin Annotations. Pengembang menambahkan anotasi @Module dan @KoinComponent, dan plugin menghasilkan kode validasi yang dijalankan saat pembangunan. Namun, keunggulan utama Koin — tidak adanya pembuatan kode — hilang dalam mode ini, sehingga sebagian besar tim terus menggunakan pendekatan DSL klasik dengan pemeriksaan runtime melalui tes.

Metode injeksi dependensi di Koin

Koin menyediakan beberapa metode injeksi dependensi: by inject(), get(), dan pengiriman langsung melalui konstruktor. Pemilihan metode tergantung pada konteks penggunaan.

by inject() — injeksi malas

Delegasi by inject — metode injeksi paling umum di ViewModel dan fragmen Android. Dependensi diinisialisasi secara malas — hanya saat pertama kali mengakses properti. Ini efisien untuk layanan yang membutuhkan banyak sumber daya yang mungkin tidak diperlukan segera.

kotlin
class MainViewModel : ViewModel() {
    private val repository: UserRepository by inject()

    fun loadUsers() {
        repository.fetchAll()
    }
}

get() — pengambilan eksplisit

Fungsi get mengembalikan instansi dependensi segera. Digunakan di dalam lambda pabrik saat registrasi atau ketika dependensi diperlukan dalam konteks sinkron tanpa inisialisasi malas. Tidak seperti by inject(), get() tidak mendukung pemuatan malas dan memerlukan container sudah diinisialisasi pada saat pemanggilan.

Modul dan scope di Koin

Scope di Koin — mekanisme pengikatan siklus hidup dependensi ke komponen tertentu, seperti Activity, Fragment, atau sesi pengguna. Ini adalah fungsionalitas kunci untuk manajemen memori di aplikasi Android.

scope — pengikatan ke komponen

Fungsi scope di dalam modul membuat scope yang hidup selama komponen terkait masih hidup. Semua dependensi yang terdaftar di scope dihancurkan saat ditutup, mencegah kebocoran memori.

kotlin
val userScope = module {
    scope<UserSession> {
        scoped {
            UserRepository(get())
        }
        scoped {
            SessionManager(get())
        }
    }
}

Fungsi scoped mendaftarkan dependensi yang hanya akan ada di dalam scope. Saat scope ditutup, semua objek scoped menjadi tidak dapat diakses oleh pengumpul sampah.

single vs factory

single — registrasi instansi tunggal untuk seluruh aplikasi dengan inisialisasi malas. Digunakan untuk layanan tanpa status: klien jaringan, cache, logger.

factory — setiap panggilan get() membuat instansi baru. Diterapkan untuk ViewModel, repositori, dan objek dengan status di mana instansi segar penting setiap kali diakses.

Koin di proyek Android

Integrasi Koin ke proyek Android sangat minimal: cukup tambahkan dependensi di build.gradle dan panggil startKoin di Application.onCreate. Koin menyediakan modul untuk integrasi dengan Jetpack Compose, Navigation, dan WorkManager, menjadikannya alternatif lengkap untuk Hilt.

Pustaka khusus koin-android-compose memungkinkan injeksi dependensi langsung di fungsi Composable melalui fungsi koinViewModel() dan koinInject(). Ini menghilangkan kebutuhan untuk meneruskan container melalui parameter setiap layar dan membuat kode ViewModel lebih bersih berkat pengikatan otomatis ke siklus hidup.

Menurut Google I/O 2024, Jetpack Compose telah menjadi framework utama untuk proyek Android baru. Koin menyediakan dukungan native Compose tanpa konfigurasi tambahan, secara otomatis menghubungkan scope ke siklus hidup ViewModel melalui koinViewModel() dengan mempertimbangkan konteks coroutine.

Untuk pengujian, Koin menyediakan fungsi koinTest dan koinTestRule yang membuat container tes terisolasi dengan modul tes dan secara otomatis menutupnya setelah tes selesai. Ini memastikan isolasi tes dan mencegah kebocoran status antar kasus tes.

Integrasi Koin dengan Jetpack Navigation diimplementasikan melalui modul koin-androidx-navigation. ViewModel setiap layar secara otomatis menerima dependensi melalui by viewModel() dengan pengiriman SavedStateHandle untuk mempertahankan status saat rotasi layar dan pemulihan setelah aplikasi diminimalkan.

Untuk pengujian unit ViewModel dengan Koin, gunakan koinTestRule dari pustaka koin-test-junit5 atau koin-test-junit4. Aturan ini membuat container terisolasi dengan modul tes sebelum setiap tes dan secara otomatis menutupnya setelah selesai, mencegah kebocoran status antar kasus tes. Dependensi nyata digantikan dengan mock melalui MockK: modul dengan registrasi single { mockk() } menimpa modul utama, dan ViewModel dalam tes menerima perilaku dependensi yang dapat diprediksi.

Salah satu kemampuan kunci Koin 3.x adalah dukungan untuk Ktor untuk membuat aplikasi server di Kotlin dan Compose Multiplatform untuk aplikasi desktop. Ini menjadikan Koin satu-satunya framework DI yang mencakup ketiga platform Kotlin tanpa mengubah paradigma injeksi. Modul koin-ktor memungkinkan registrasi dependensi melalui install(Koin) di blok Application dan injeksi layanan ke rute melalui by inject() sama seperti di Android. Ini menjadikan Koin solusi DI universal untuk proyek Kotlin dengan arsitektur apa pun — dari klien seluler hingga backend server.

Integrasi Koin dengan Jetpack Navigation melalui modul koin-androidx-navigation menghilangkan kebutuhan untuk membuat ViewModelProvider.Factory secara manual untuk setiap layar. Untuk proyek multi-modul, Koin mendukung pemuatan malas modul melalui loadKoinModules, memungkinkan koneksi konfigurasi DI setiap modul fitur secara independen.

Pertanyaan yang sering diajukan

Apa perbedaan Koin dengan Dagger Hilt?

Koin bekerja di runtime tanpa pembuatan kode dan anotasi, yang mempercepat pembangunan, tetapi tidak memeriksa grafik dependensi pada tahap kompilasi. Hilt menghasilkan kode saat kompilasi dan mendeteksi kesalahan DI lebih awal, tetapi memerlukan konfigurasi rumit dan memperlambat build.

Apakah Koin mendukung Kotlin Multiplatform?

Ya, Koin sepenuhnya mendukung Kotlin Multiplatform. Pustaka koin-core bekerja di semua platform Kotlin, dan koin-android serta koin-compose menambahkan kemampuan khusus platform untuk Android dan iOS.

Bagaimana menangani dependensi siklik di Koin?

Dependensi siklik menyebabkan StackOverflowError di runtime. Koin tidak mendeteksinya secara otomatis. Solusi — refaktor arsitektur: ekstraksi antarmuka umum, penggunaan pola Listener/Observer, atau pemutusan siklus melalui pabrik dengan inisialisasi tertunda.

Apakah scope perlu ditutup secara manual?

Di Android, scope dapat diikat ke siklus hidup Activity atau Fragment melalui AndroidScope. Saat komponen dihancurkan, Koin secara otomatis menutup scope yang sesuai. Di scope khusus (sesi pengguna), penutupan dilakukan secara manual dengan memanggil scope.close.

Bagaimana cara menguji kode dengan Koin?

Gunakan fungsi koinTest dari modul koin-test. Ini membuat container terisolasi dengan modul tes yang secara otomatis ditutup setelah tes. Dependensi nyata digantikan dengan mock melalui modul dengan Mockito atau MockK.

Kesimpulan

  • Koin — framework DI untuk Kotlin dengan DSL tanpa refleksi, anotasi, dan pembuatan kode.
  • Modul mengelompokkan registrasi melalui single (singleton) dan factory (instansi baru).
  • startKoin menginisialisasi container global yang dapat diakses melalui by inject() dan get().
  • Scope mengikat siklus hidup dependensi ke siklus hidup komponen Android.
  • Injeksi di Compose dilakukan melalui koinViewModel() dan koinInject().
  • Koin mendukung Kotlin Multiplatform, memungkinkan pendekatan DI terpadu di semua platform.
  • Kesalahan DI terdeteksi di runtime, oleh karena itu cakupan tes konfigurasi wajib dilakukan.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga