Skip to content

Build-Time Config Access

Kayan can expose resolved config values during Gradle configuration, not just in generated Kotlin source. This lets build logic use the same validated config that shared code reads later.

Use buildValue("json_key") when Gradle decisions need to depend on config:

@file:OptIn(io.kayan.gradle.ExperimentalKayanGradleApi::class)
kayan {
flavor.set("prod")
schema {
boolean("feature_search_enabled",
"FEATURE_SEARCH_ENABLED")
string("brand_name", "BRAND_NAME")
enumValue("release_stage",
"RELEASE_STAGE",
enumTypeName = "sample.ReleaseStage")
}
}
val isSearchEnabled =
kayan.buildValue("feature_search_enabled")
.asBoolean()
dependencies {
if (isSearchEnabled) {
implementation("com.example:search-sdk:1.0.0")
}
}

By design, this API is meant for non-sensitive build configuration. If a value is appropriate for Gradle to read during configuration, it is usually fine for buildValue(). Secrets such as API keys, passwords, and tokens should stay in dedicated secret-management or environment-specific secure storage instead. See Security for the trust model behind buildValue() and custom adapters.

Use buildValue() when Gradle itself needs the answer:

  • conditional dependencies
  • source set or task configuration
  • build flags that should be decided during configuration

Use the generated KayanConfig object when application or shared Kotlin code needs the value at compile time or runtime.

buildValue("key") returns a KayanBuildValue with three styles of accessors.

These resolve immediately and return plain Kotlin values. Use them when the build script needs the answer right now, for example inside if and when:

kayan.buildValue("brand_name").asString()
kayan.buildValue("feature_search_enabled").asBoolean()
kayan.buildValue("max_workspace_count").asInt()
kayan.buildValue("max_cache_bytes").asLong()
kayan.buildValue("rollout_ratio").asDouble()
kayan.buildValue("support_links").asStringList()
kayan.buildValue("support_labels").asStringMap()
kayan.buildValue("regional_support_links").asStringListMap()

If a resolved value may be null, use the OrNull variants:

val supportEmail =
kayan.buildValue("support_email")
.asStringOrNull()

These do the same type checks, but return a Gradle Provider<T> instead of the plain value. Use them for task inputs and other lazy Gradle wiring:

val brandName = kayan.buildValue("brand_name").asString()
val brandNameProvider = kayan.buildValue("brand_name").asStringProvider()
  • asString() resolves immediately during configuration
  • asStringProvider() defers resolution until Gradle needs the value

That difference matters most when assigning into Property<T>, ListProperty<T>, or other provider-based Gradle APIs:

@file:OptIn(io.kayan.gradle.ExperimentalKayanGradleApi::class)
abstract class PrintBrandTask : DefaultTask() {
@get:Input
abstract val brandName: Property<String>
@TaskAction
fun printBrand() {
println(brandName.get())
}
}
tasks.register<PrintBrandTask>("printBrand") {
brandName.set(
kayan.buildValue("brand_name")
.asStringProvider()
)
}

At Gradle configuration time, enums are exposed by their normalized name rather than by instantiating the enum type:

when (kayan.buildValue("release_stage").asEnumName()) {
"PROD" -> println("production build")
"BETA" -> println("beta build")
}

asString() also works for enum values and returns their normalized constant names.

buildValue() fails early with Gradle-friendly messages:

  • unknown schema key: "Key '<key>' is not defined in the Kayan schema" with close-match suggestions
  • type mismatch: "Key '<key>' is <actual kind>, cannot access as <requested type>"
  • null through non-null accessor: "Key '<key>' is null; use as<Type>OrNull() instead"
  • flavor must be configured before buildValue() is used
  • keys must still be declared in the Kayan schema {}
  • build-time access returns raw Gradle-friendly primitives and collections
  • custom adapters are not applied at configuration time

That last point is intentional: Gradle build logic usually needs Boolean, String, or List<String>, not consumer-owned domain types.

buildValue() is backed by a Gradle ValueSource, so file changes to the configured inputs invalidate resolution while configuration-cache-friendly builds can still reuse the requested key between runs without serializing unrelated resolved values.