# Android Dependency Injection: Hilt vs Koin – Complete Gids en Sollicitatievragen 2026 > Uitgebreide vergelijking van Hilt en Koin voor Android Dependency Injection met codevoorbeelden, benchmarks en veelgestelde sollicitatievragen voor 2026. - Published: 2026-05-24 - Updated: 2026-05-24 - Author: SharpSkill - Tags: android, kotlin, dependency-injection, hilt, koin - Reading time: 12 min --- Dependency Injection (DI) behoort tot de fundamentele architectuurprincipes in Android-ontwikkeling. In plaats van afhankelijkheden direct binnen een klasse aan te maken, worden ze van buitenaf aangeleverd — dit verbetert testbaarheid, onderhoudbaarheid en modulariteit. In 2026 domineren twee frameworks dit domein: [Hilt](https://dagger.dev/hilt/) in versie 2.57.1, Googles officiële compile-time-oplossing gebouwd op Dagger, en [Koin](https://insert-koin.io/) in versie 4.2.1, een lichtgewicht runtime service locator met een pure Kotlin DSL. De keuze tussen beide beïnvloedt buildtijden, opstartperformance, testbaarheid en hoe snel nieuwe teamleden productief worden. > **Compile-Time vs Runtime DI** > > Hilt valideert de volledige dependency graph tijdens compilatie en laat de build falen als er een binding ontbreekt. Koin lost afhankelijkheden op tijdens runtime via een Kotlin DSL en detecteert configuratiefouten pas wanneer het betreffende codepad wordt uitgevoerd. Dit fundamentele verschil bepaalt alle afwegingen tussen de twee frameworks. ## Hoe Hilt Dependency Injection onder de motorkap werkt Hilt genereert Dagger-componenten die zijn gekoppeld aan Android lifecycle-klassen. De `@HiltAndroidApp`-annotatie activeert codegeneratie tijdens compile-time en produceert factories en providers voor elke gedeclareerde binding. KSP (Kotlin Symbol Processing) heeft KAPT vervangen als aanbevolen annotation processor sinds Hilt 2.48, waardoor de verwerkingstijd ruwweg gehalveerd is. Een typische Hilt-configuratie bestaat uit drie onderdelen: een module die bindings declareert, een entry point (Activity, Fragment of ViewModel) en de Application-klasse geannoteerd met `@HiltAndroidApp`. ```kotlin // AppModule.kt @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideUserRepository( retrofit: Retrofit ): UserRepository { return UserRepositoryImpl(retrofit.create(UserApi::class.java)) } } ``` ```kotlin // UserViewModel.kt @HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() { private val _users = MutableStateFlow>(emptyList()) val users: StateFlow> = _users.asStateFlow() fun loadUsers() { viewModelScope.launch { _users.value = userRepository.getUsers() } } } ``` De compiler verifieert dat er een geldige provider bestaat voor `UserRepository` voordat de app ooit wordt uitgevoerd. Ontbrekende bindings verschijnen als buildfouten, niet als runtime crashes. ## Koin-configuratie en de Kotlin DSL-aanpak Koin hanteert de tegenovergestelde benadering: geen codegeneratie, geen annotation processing. Afhankelijkheden worden gedeclareerd in pure Kotlin via een DSL, en het framework lost ze op tijdens runtime via een globaal serviceregister. Koin 4.2 introduceerde Lazy Modules voor parallel laden bij het opstarten en een nieuwe `CoreResolverV2`-engine die scope-resolutie optimaliseert. ```kotlin // AppModule.kt val appModule = module { // Singleton Retrofit-instantie single { Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } // Singleton repository gekoppeld aan zijn interface single { UserRepositoryImpl(get().create(UserApi::class.java)) } // ViewModel met geïnjecteerde repository viewModel { UserViewModel(get()) } } ``` ```kotlin // MyApplication.kt class MyApplication : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApplication) modules(appModule) } } } ``` De DSL leest natuurlijk en vereist geen annotation processing-plugin in de Gradle-configuratie. De keerzijde: een typfout in `get()`-resolutie manifesteert zich pas tijdens runtime wanneer dat specifieke injectiepunt wordt uitgevoerd. ## Performancebenchmarks: buildtijd vs runtimekosten De performancevraag komt in vrijwel elk [Android-sollicitatiegesprek](/technologies/android/interview-questions/android-dependency-injection) naar voren. Concrete cijfers wegen zwaarder dan meningen. | Metriek | Hilt 2.57 (KSP) | Koin 4.2 | |---------|-----------------|----------| | Clean build overhead | +8-15s (KSP-codegeneratie) | ~0s (geen codegeneratie) | | Incrementele build overhead | +2-4s | ~0s | | App-opstart (50 bindings) | ~0ms (vooraf gegenereerde code) | ~5-15ms (graph-resolutie) | | App-opstart (500 bindings) | ~0ms | ~30-80ms | | APK-grootte impact | +200-400 KB (gegenereerde code) | +100 KB (runtime-bibliotheek) | | Detectie ontbrekende bindings | Compilatiefout | Runtime crash | Voor projecten met minder dan 100 bindings blijft de runtime-overhead van Koin onmerkbaar. Boven de 300 bindings wordt de opstartkost meetbaar, hoewel Koins Lazy Modules dit verzachten door het laden van modules te paralleliseren. > **KSP vs KAPT** > > Overstappen van KAPT naar KSP voor Hilt-verwerking vermindert de annotation processing-tijd met 40-60%. Elk project dat nog KAPT met Hilt gebruikt, zou onmiddellijk naar KSP moeten migreren. Hilt ondersteunt KSP sinds versie 2.48. ## Teststrategieën met elk framework Testbaarheid is het gebied waar de architecturale verschillen praktisch voelbaar worden. Hilt biedt `@TestInstallIn` om productiemodules tijdens compile-time te vervangen door test doubles. Koin biedt `loadKoinModules()` om definities tijdens runtime te overschrijven. ```kotlin // Hilt-testmodule — vervangt AppModule-bindings in tests @Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AppModule::class] ) object FakeAppModule { @Provides @Singleton fun provideUserRepository(): UserRepository { return FakeUserRepository() // In-memory test double } } ``` ```kotlin // Koin-test — overschrijving tijdens runtime class UserViewModelTest : KoinTest { @Before fun setUp() { startKoin { modules( module { single { FakeUserRepository() } viewModel { UserViewModel(get()) } } ) } } @Test fun `loads users from repository`() { val viewModel: UserViewModel = get() viewModel.loadUsers() assertEquals(3, viewModel.users.value.size) } @After fun tearDown() { stopKoin() } } ``` Hilt-tests vangen verkeerd geconfigureerde testmodules op tijdens compile-time. Koin-tests vereisen zorgvuldig lifecycle-beheer (`startKoin`/`stopKoin`), maar bieden meer flexibiliteit voor gedeeltelijke module-overschrijvingen. ## Multi-module architectuur: DI schalen over feature-grenzen Grote Android-projecten splitsen features op in aparte Gradle-modules. Het DI-framework moet modulegrenzen schoon ondersteunen. Met Hilt declareert elke feature-module zijn eigen `@Module` geannoteerd met `@InstallIn`. Hilt voegt alle modules samen tot één componenthiërarchie tijdens compile-time. De [MVVM-architectuur](/blog/android/mvvm-vs-mvi-architecture) past van nature bij Hilts scoped componenten. ```kotlin // feature-payments/PaymentModule.kt @Module @InstallIn(ViewModelComponent::class) object PaymentModule { @Provides fun providePaymentGateway( retrofit: Retrofit // Aangeleverd door de :app-module ): PaymentGateway { return StripePaymentGateway(retrofit.create(PaymentApi::class.java)) } } ``` Met Koin exporteren feature-modules hun `module {}`-declaraties, en de app-module laadt ze allemaal bij het opstarten. Koins Lazy Modules in versie 4.2 maken uitgesteld laden van feature-modules mogelijk tot het eerste gebruik. ```kotlin // feature-payments/paymentModule.kt val paymentModule = module { factory { StripePaymentGateway(get().create(PaymentApi::class.java)) } } // app/MyApplication.kt — laadt alle feature-modules startKoin { modules(appModule, paymentModule, analyticsModule) } ``` Hilt dwingt zichtbaarheid van afhankelijkheden af via component scopes. Koin vertrouwt op conventies — elke module kan de definities van elke andere module benaderen, wat flexibiliteit biedt maar kan leiden tot impliciete koppeling. ## Kotlin Multiplatform overwegingen Koin ondersteunt [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) (KMP) van nature. Dezelfde `module {}`-DSL werkt op Android, iOS, Desktop en Web. Hilt is uitsluitend voor Android — het is afhankelijk van Android-specifieke lifecycle-componenten en de Dagger annotation processor. Voor projecten die meerdere platformen targeten, is Koin de enige haalbare optie van de twee. Gedeelde business logic-modules kunnen hun afhankelijkheden eenmalig declareren en ze over alle targets injecteren. ## Veelgestelde sollicitatievragen over Android DI Deze vragen komen regelmatig voor in [technische Android-sollicitatiegesprekken](/technologies/android). Elk antwoord blijft bondig en focust op wat interviewers verwachten. **V: Wat is het verschil tussen compile-time en runtime dependency injection?** Compile-time DI (Hilt/Dagger) genereert injectiecode tijdens de build. De compiler valideert de volledige dependency graph en vangt ontbrekende bindings op vóór runtime. Runtime DI (Koin) lost afhankelijkheden op wanneer ze voor het eerst worden opgevraagd, via een service registry-patroon. Compile-time DI levert een snellere opstart maar tragere builds; runtime DI heeft geen build-overhead maar stelt foutdetectie uit. **V: Welke Hilt component scopes bestaan er en hoe verhouden ze zich tot Android lifecycles?** `SingletonComponent` leeft gedurende de gehele applicatie. `ActivityRetainedComponent` overleeft configuratiewijzigingen. `ViewModelComponent` is gebonden aan de lifecycle van een ViewModel. `ActivityComponent`, `FragmentComponent` en `ViewComponent` volgen hun respectievelijke Android lifecycle owners. Aangepaste scopes kunnen deze hiërarchie uitbreiden. **V: Hoe behandelt Koin ViewModel-injectie in Jetpack Compose?** Koin biedt `koinViewModel()` als Composable-functie die een ViewModel aanmaakt of ophaalt met scope tot de dichtstbijzijnde `ViewModelStoreOwner`. Sinds Koin 4.2 bindt `koinNavViewModel()` ViewModels aan navigation graph-items bij gebruik van [Jetpack Compose Navigation](/blog/android/jetpack-compose-interview-questions). **V: Wanneer zou Koin een betere keuze zijn dan Hilt?** Koin past beter bij KMP-projecten (Hilt is alleen voor Android), kleine tot middelgrote apps waar buildtijd zwaarder weegt dan opstarttijd, en teams die de voorkeur geven aan een expliciete Kotlin DSL boven annotatie-gedreven configuratie. Prototyping en proof-of-concept-projecten profiteren eveneens van Koins minimale setup. > **Veelgemaakte fout in sollicitatiegesprekken** > > Koin een "dependency injection framework" noemen is technisch onnauwkeurig. Koin is een service locator — afhankelijkheden worden opgehaald via `get()` in plaats van aangeleverd via constructor injection. Interviewers die dit onderscheid kennen, verwachten dat kandidaten dit erkennen. Hilt/Dagger voert echte dependency injection uit via gegenereerde constructor-aanroepen. ## Besliskader: kiezen tussen Hilt en Koin | Factor | Hilt | Koin | |--------|------|------| | Graph-validatie | Compile-time | Runtime | | Impact op buildtijd | Hoger (KSP-codegen) | Geen | | Opstartkosten | Vrijwel nul | Schaalt met graph-grootte | | Leercurve | Steiler (Dagger-concepten) | Geleidelijk (pure Kotlin DSL) | | KMP-ondersteuning | Nee | Ja | | Jetpack-integratie | Diep (officieel Google) | Goed (community) | | Teamschaalbaarheid | Sterker (afgedwongen scopes) | Flexibel (conventie-gebaseerd) | | Testen | `@TestInstallIn` (compile-safe) | `loadKoinModules` (runtime) | Geen van beide frameworks is universeel superieur. De keuze hangt af van projectgrootte, teamervaring en doelplatformen. ## Conclusie - Hilt 2.57 met KSP levert compile-time graph-validatie en vrijwel geen opstartkosten, waardoor het de sterkere keuze is voor grote, single-platform Android-projecten met strenge betrouwbaarheidseisen - Koin 4.2 met Lazy Modules en `CoreResolverV2` verkleint het verschil in opstartperformance terwijl het zero build-overhead en volledige KMP-compatibiliteit behoudt - Beide frameworks ondersteunen multi-module architecturen, maar Hilt dwingt scope-grenzen af tijdens compile-time terwijl Koin vertrouwt op teamconventies - Voor [Android-sollicitatievoorbereiding](/technologies/android) is het begrijpen van de compile-time vs runtime afweging en het kunnen verwoorden wanneer elk framework het beste past de verwachte basis - Migreren tussen frameworks is niet triviaal — de initiële keuze moet rekening houden met de langetermijn platform- en schaalstrategie van het project --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/android/android-dependency-injection-hilt-vs-koin