Skip to content

@Provides

Providers can be defined in graphs or supertypes that graphs extend. Defining them in supertypes allows for them to be reused across multiple graphs and organize providers into logic groups. This is similar to how modules in Dagger work.

interface NetworkProviders {
  @Provides
  fun provideHttpClient(): HttpClient = HttpClient()
}

@DependencyGraph
interface AppGraph : NetworkProviders

Providers should be private by default.

Tip

It’s recommended to not call providers from each other.

Overrides

It is an error to override providers declarations. While it can be enticing for testing reasons to try to replicate Dagger 1’s module overrides, it quickly becomes difficult to reason about in code gen.

  • What if you override with sub/supertypes?
  • What if your override’s implementation needs different dependencies?

To the testing end, it is recommended to instead leverage the DependencyGraph.excludes + ContributesTo.replaces APIs in merging.

// Don't do this pattern!
interface NetworkProviders {
  @Provides
  fun provideHttpClient(): HttpClient = HttpClient()
}

@DependencyGraph
interface TestAppGraph : NetworkProviders {
  // This will fail to compile
  override fun provideHttpClient(): HttpClient = TestHttpClient()
}

Companion Providers

Providers can alternatively be implemented in companion objects for staticization.

interface MessageGraph {
  val message: String
  companion object {
    @Provides
    private fun provideMessage(): String = "Hello, world!"
  }
}

Implementation Notes

private interface functions are not usually visible to downstream compilations in IR. To work around this, Metro will use a new API in Kotlin 2.1.20 to add custom metadata to the parent class to denote these private providers’ existence and where to find them.