Getting started

This page takes a JVM project from nothing to a working module. For Kotlin Multiplatform projects, see Setup.

  1. Apply the KSP plugin, and add both Inara artifacts:

    build.gradle.kts
    plugins {
        kotlin("jvm") version "2.4.20"
        id("com.google.devtools.ksp") version "2.3.12" (1)
    }
    
    dependencies {
        implementation("org.kodein.di.inara:inara-runtime:0.1.0") (2)
        ksp("org.kodein.di.inara:inara-processor:0.1.0") (3)
    }
    1 Apply the KSP plugin that corresponds to the Kotlin version you are using.
    2 The runtime: Binding types and annotations.
    3 The processor that generates module implementations.
  2. Declare a module as an interface annotated with @DIModule:

    AppModule.kt
    @DIModule
    interface AppModule {
        val databaseUrl: String
        fun database(): Database
        fun userRepository(): UserRepository
    }
  3. Build the project once, so that the processor generates the AppModule(…​) builder function.

    Your IDE only sees generated code once it has been generated, so the builder appears as unresolved until the first build.
  4. Build the module, giving one Binding per member:

    Main.kt
    fun main() {
        val app = AppModule(
            databaseUrl = Binding.value("jdbc:h2:mem:app"), (1)
            database = Binding.single { Database.connect(databaseUrl) }, (2)
            userRepository = Binding.provider { UserRepository(database()) }, (3)
        )
    
        val repository = app.userRepository()
    }
    1 value binds a pre-built value.
    2 single builds the value once, on first access, and keeps it forever.
    3 provider builds a new value on every access.

    Each binding body runs with the module as its receiver, which is why databaseUrl and database() can be read directly.

  5. Optionally, let Inara build your own classes for you with @DIFactory:

    UserController.kt
    class UserController(val repository: UserRepository) (1)
    
    @DIFactory(builds = UserController::class, from = AppModule::class)
    object UserControllerFactory
    1 A plain class that knows nothing about Inara.

    The processor generates UserControllerFactory.UserController(module: AppModule), which finds the repository argument in AppModule by its type:

    val controller = UserControllerFactory.UserController(app)

That’s it! From here, Declaring a module and Bindings explain everything a module can hold.