Kayan
Kotlin Multiplatform Gradle plugin for generating typed BuildConfig-style objects from layered JSON configs.
Install / Use
/learn @MohamadJaara/KayanREADME
Kayan is a Kotlin Gradle plugin that generates a typed Kotlin object from layered JSON and YAML config files.
It works with Kotlin Multiplatform, Kotlin/JVM, and Kotlin Android projects, so shared code can read
config directly without platform-specific BuildConfig wiring.
The name comes from the Arabic word كيان (Kayan), which means "entity", "structure", or "being".
JSON is valid YAML, but Kayan still makes the format choice explicit so your builds do not develop a split personality.
Why Kayan
- Keep config in JSON or YAML while exposing a typed Kotlin API.
- Let the consuming app own the schema and generated property names.
- Resolve layered defaults and overrides deterministically at build time.
- Work in shared Kotlin across KMP, JVM, and Android modules.
- Reuse resolved values inside Gradle itself with
buildValue("key").
Quick start
Add Maven Central to Gradle plugin resolution when consuming the published plugin:
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
Add a config file:
{
"flavors": {
"prod": {
"api_base_url": "https://api.example.com",
"feature_search_enabled": false
},
"dev": {
"api_base_url": "https://dev.example.com",
"feature_search_enabled": true
}
},
"brand_name": "Example App"
}
YAML works too:
flavors:
prod:
api_base_url: https://api.example.com
feature_search_enabled: false
dev:
api_base_url: https://dev.example.com
feature_search_enabled: true
brand_name: Example App
Apply the plugin and declare your schema:
plugins {
kotlin("multiplatform") version "<kotlin-version>"
id("io.github.mohamadjaara.kayan") version "<kayan-version>"
}
kayan {
packageName.set("sample.generated")
flavor.set("prod")
schema {
string("api_base_url", "API_BASE_URL", required = true)
boolean("feature_search_enabled", "FEATURE_SEARCH_ENABLED")
string("brand_name", "BRAND_NAME")
}
}
Generate the config source:
./gradlew generateKayanConfig
Use the generated object from shared code:
import sample.generated.SampleConfig
val baseUrl = SampleConfig.API_BASE_URL
val searchEnabled = SampleConfig.FEATURE_SEARCH_ENABLED
val brandName = SampleConfig.BRAND_NAME
Generated source lands in build/generated/kayan/kotlin and is wired into the appropriate source
set automatically.
Target-specific overrides
For Kotlin Multiplatform projects that need one config API in shared code but different values per
target, add targets in the config file and configure Kayan targets:
brand_name: Example App
flavors:
prod:
targets:
android:
bundle_id: com.example.android
ios:
bundle_id: com.example.ios
kayan {
packageName.set("sample.generated")
flavor.set("prod")
targets("android", "ios")
}
Kayan generates an expect object into commonMain and matching actual object declarations into
the configured target source sets.
For non-standard source set names or custom target labels, use the DSL form:
kayan {
targets {
ios()
jvm("desktop")
sourceSet("appleMain", "ios-shared")
}
}
By design, Kayan is a fit for non-sensitive build and app configuration. Values declared in the schema can be generated into source or consumed by Gradle during the build, so secrets such as API keys, passwords, and tokens should stay in dedicated secret-management or environment-specific secure storage.
buildValue()is experimental. Opt in with@file:OptIn(io.kayan.gradle.ExperimentalKayanGradleApi::class)when using the Gradle build-time API frombuild.gradle.kts.
Build-time config access
When Gradle logic needs the same resolved config, use buildValue() directly in
build.gradle.kts:
@file:OptIn(io.kayan.gradle.ExperimentalKayanGradleApi::class)
val isSearchEnabled =
kayan.buildValue("feature_search_enabled")
.asBoolean()
dependencies {
if (isSearchEnabled) {
implementation("com.example:search-sdk:1.0.0")
}
}
This is useful for conditional dependencies, task inputs, and other configuration-time
decisions. Provider variants such as asStringProvider() are also available for lazy task
wiring.
Learn more
- Overview
- Quick Start
- Gradle Usage
- Build-Time Config Access
- Resolution Order
- JSON Shape
- Schema Types
- Validation
- Schema Export
- BuildConfig Migration
- White-label Configs
- Commands
- Threat Model
Development
Build everything:
./gradlew build
Run plugin tests:
./gradlew :gradle-plugin:test
Install the local git hooks:
pre-commit install --install-hooks
Sample app
The sample app in sample/ demonstrates local plugin consumption, generated config usage, and
Compose Multiplatform targets for desktop, web, and Apple platforms.
Run the desktop sample:
./gradlew -p sample run
Run the web sample:
./gradlew -p sample wasmJsBrowserDevelopmentRun
More sample details are in sample/README.md.
