Blok dependencies di build.gradle.kts adalah bagian yang paling sering berubah sepanjang siklus hidup proyek. Setiap library yang kita tambahkan, baik untuk produksi maupun test, dideklarasikan di sini. Pemilihan configuration yang tepat (implementation vs api vs compileOnly) memengaruhi waktu kompilasi inkremental, ukuran artefak final, dan batas API yang diekspos ke konsumer. Pada chapter ini kita akan membahas setiap configuration, format koordinat dependensi, serta pola deklarasi yang umum.

Configuration di Gradle #

Configuration adalah label yang menentukan kapan sebuah dependensi tersedia di classpath. Lima configuration berikut paling sering dipakai:

ConfigurationSaat compileSaat runtimeDiekspos ke konsumer
implementationYaYaTidak
apiYaYaYa
compileOnlyYaTidakTidak
runtimeOnlyTidakYaTidak
testImplementationHanya test compileHanya test runtimeTidak

Pilihan configuration memengaruhi rantai dependensi. Misalnya, bila modul A memakai implementation ke modul B, dan B memakai library C, maka A tidak dapat melihat class-class dari C langsung. Sebaliknya, bila A memakai api ke B, A dapat melihat class-class C di signature public B.

Format Koordinat #

Setiap dependensi dideklarasikan dalam format group:name:version:

  • group: organisasi/namespace (mis. org.jetbrains.kotlinx, com.fasterxml.jackson.core)
  • name: nama artefak (mis. kotlinx-coroutines-core, jackson-databind)
  • version: nomor versi (mis. 1.8.1, 2.17.0)

Versi bisa berupa angka tetap (1.8.1), range ([1.0,2.0)), atau dynamic version (+, latest.release). Hindari dynamic version di CI karena membuat build tidak reproducible.

Deklarasi Dependensi #

kotlin build.gradle.kts — dependencies
dependencies {
    // Produksi: library utama
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")

    // Logging facade (compile) + implementation (runtime)
    compileOnly("org.slf4j:slf4j-api:2.0.13")
    runtimeOnly("ch.qos.logback:logback-classic:1.5.6")

    // HTTP client
    implementation("io.ktor:ktor-client-core:2.3.12")
    implementation("io.ktor:ktor-client-cio:2.3.12")

    // Test
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    testImplementation("io.mockk:mockk:1.13.10")
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1")
}

Mari kita bedah contoh di atas:

  1. kotlinx-coroutines-core sebagai implementation: library ini dipakai internal modul; tidak perlu diekspos ke konsumer.
  2. slf4j-api sebagai compileOnly: kita mengkode dengan API SLF4J, tetapi implementasi logback disediakan oleh konsumer modul. Pola ini lazim untuk library.
  3. logback-classic sebagai runtimeOnly: hanya dibutuhkan saat runtime; tidak ada class dari logback yang muncul di signature public modul.
  4. junit-jupiter sebagai testImplementation: hanya tersedia di source set test; tidak disertakan di JAR produksi.

Demonstrasi Configuration #

Kode berikut mencantumkan daftar configuration utama beserta contoh deklarasi.

kotlin
fun main() {
    println("=== Konfigurasi Dependensi Gradle ===")
    println("Empat configuration utama di Gradle:")
    println()
    println("  implementation   - dependensi saat compile + runtime, tidak diekspos ke konsumer")
    println("  api              - dependensi saat compile + runtime, diekspos ke konsumer")
    println("  testImplementation - dependensi hanya untuk src/test saat compile + runtime")
    println("  compileOnly      - dependensi hanya saat compile, tidak di-runtime")
    println("  runtimeOnly      - dependensi hanya saat runtime, tidak saat compile")
    println("  annotationProcessor / ksp - pemroses anotasi (KAPT/KSP)")
    println()
    println("Contoh deklarasi:")
    println("  implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1\")")
    println("  testImplementation(\"org.junit.jupiter:junit-jupiter:5.10.0\")")
    println("  compileOnly(\"org.slf4j:slf4j-api:2.0.13\")")
    println("  runtimeOnly(\"ch.qos.logback:logback-classic:1.5.6\")")
    println()
    println("Format koordinat: group:name:version")
    println("  group   : organisasi (mis. org.jetbrains.kotlinx)")
    println("  name    : artefak (mis. kotlinx-coroutines-core)")
    println("  version : versi (mis. 1.8.1)")
}

Output yang Dihasilkan:

text
=== Konfigurasi Dependensi Gradle ===
Empat configuration utama di Gradle:

  implementation   - dependensi saat compile + runtime, tidak diekspos ke konsumer
  api              - dependensi saat compile + runtime, diekspos ke konsumer
  testImplementation - dependensi hanya untuk src/test saat compile + runtime
  compileOnly      - dependensi hanya saat compile, tidak di-runtime
  runtimeOnly      - dependensi hanya saat runtime, tidak saat compile
  annotationProcessor / ksp - pemroses anotasi (KAPT/KSP)

Contoh deklarasi:
  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
  testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
  compileOnly("org.slf4j:slf4j-api:2.0.13")
  runtimeOnly("ch.qos.logback:logback-classic:1.5.6")

Format koordinat: group:name:version
  group   : organisasi (mis. org.jetbrains.kotlinx)
  name    : artefak (mis. kotlinx-coroutines-core)
  version : versi (mis. 1.8.1)

Mari kita telaah kode di atas:

  1. Daftar configuration: tabel ringkas yang menunjukkan kapan setiap configuration relevan. Pembaca dapat memakainya sebagai panduan cepat saat menulis dependencies block baru.
  2. Contoh koordinat: menampilkan string lengkap group:name:version. Format ini adalah notasi string yang dipakai Gradle; notasi alternatif berbasis map (group = "...", name = "...", version = "...") juga valid tetapi lebih panjang.
  3. Catatan annotationProcessor / ksp: configuration khusus untuk pemroses anotasi. KAPT menambah kapt, KSP menambah ksp.

Tipe Configuration Khusus #

Beberapa configuration tambahan muncul sesuai plugin yang aktif:

kotlin Configuration berdasarkan plugin
plugins {
    kotlin("jvm")
    id("com.google.devtools.ksp")     // menambah ksp()
    kotlin("kapt")                      // menambah kapt()
}

dependencies {
    // KSP: pemroses anotasi native Kotlin
    ksp("dev.zacsweels.autodapter:autodapter-ksp:1.0.0")

    // KAPT: pemroses anotasi javac lama
    kapt("com.google.dagger:dagger-compiler:2.51.1")

    // Multiplatform: source set khusus
    // commonMain implementation(), jvmMain implementation(), dll.
}

Best Practices #

Beberapa pedoman praktis:

  • Default ke implementation. Naikkan ke api hanya bila tipe dependensi muncul di signature public modul.
  • Untuk logging: compileOnly API facade + runtimeOnly implementation. Hindari binding langsung ke Logback/Log4j.
  • Untuk library yang dipakai hanya di test: selalu testImplementation, jangan implementation.
  • Untuk versi: pakai version catalog (chapter terpisah) untuk memusatkan dan menghindari duplikasi.

Referensi Lanjutan #

  • Gradle — panduan resmi Kotlin + Gradle untuk deklarasi dependensi implementation dan api
  • Gradle User Guide — buku panduan Gradle yang merinci konfigurasi dependensi dan resolusi versi

Penutup #

Pemilihan configuration yang tepat adalah keputusan arsitektur: memengaruhi build time, binary size, dan batas API. Pada chapter berikutnya kita akan membahas task Gradle secara umum — termasuk task bawaan yang ditambahkan plugin Kotlin dan cara menulis task custom.