Skip to content

Repository files navigation

Kayan icon

Kayan

Typed layered JSON and YAML config for Kotlin Multiplatform, JVM, and Android.

CI Codecov coverage Maven Central Release License Docs

Kayan is a Kotlin Gradle plugin that turns layered JSON or YAML config into a typed Kotlin object. Kotlin Multiplatform, JVM, and Android projects can read that object 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

Kayan writes generated source to build/generated/kayan/kotlin and adds the directory to the appropriate source set.

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")
    }
}

Kayan is for non-sensitive build and app configuration. Schema values may appear in generated source or Gradle configuration, so keep API keys, passwords, tokens, and other secrets in dedicated secure storage.

buildValue() is experimental. Opt in with @file:OptIn(io.kayan.gradle.ExperimentalKayanGradleApi::class) when using the Gradle build-time API from build.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")
    }
}

Use this for conditional dependencies, task inputs, and other configuration-time decisions. Provider variants such as asStringProvider() defer resolution for lazy task wiring.

Learn more

Development

Build everything:

./gradlew build

Run plugin tests:

./gradlew :gradle-plugin:test

Sample app

The app in sample/ consumes the local plugin and uses its generated config on desktop, web, and Apple targets.

Run the desktop sample:

./gradlew -p sample run

Run the web sample:

./gradlew -p sample wasmJsBrowserDevelopmentRun

More sample details are in sample/README.md.

About

Kotlin Multiplatform Gradle plugin for generating typed BuildConfig-style objects from layered JSON configs.

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages