# BuildKonfig: a Gradle plugin that generates one BuildConfig object for Kotlin Multiplatform

> BuildKonfig is a Gradle plugin that generates a typed Kotlin object holding build-time values for Kotlin Multiplatform and Kotlin/JVM projects, so the same constants do not have to be wired separately into Android and iOS builds.

**yshrsmz/BuildKonfig** — BuildConfig for Kotlin Multiplatform Project

- Repository: https://github.com/yshrsmz/BuildKonfig
- Stars: 1,225 · Forks: 49
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/yshrsmz-buildkonfig

## The same values for Android and iOS without doing it twice

The motivation is stated in one short paragraph. Passing values from Android, iOS or any other platform code should work, but it is a hassle: setting up Android to read values from properties and add them into BuildConfig, and then doing the equivalent in iOS. The author would rather do it once. That is the entire scope of the plugin. It does not manage secrets, and it does not read environment variables at runtime. It takes values you declare in Gradle and turns them into a Kotlin object that the shared code in your project can read, so a multiplatform module has one place to look for a value that used to live in two different build systems. The plugin is published to Maven Central under the group `com.codingfeline.buildkonfig` with the artifact name `buildkonfig-gradle-plugin`.

## The version requirements are tight and not negotiable

Three requirements are listed, and the first one has a wrinkle worth knowing before you plan an upgrade. Kotlin 2.4.20 or later is required, because the plugin depends on the Kotlin Gradle Plugin 2.4.20, so declaring an older version in your own build resolves to 2.4.20 anyway. That means you cannot keep an older Kotlin compiler by pinning it; the plugin's own dependency drags it forward. Second, you need either the Kotlin Multiplatform plugin or the Kotlin/JVM plugin applied to the project, and JavaScript is reached through the multiplatform `js()` target rather than through a separate Kotlin/JS plugin. Third, Gradle 8.14 or later. For a team on an older Gradle, the plugin is simply not available, and there is no compatibility shim described anywhere in the documentation.

## Configuring the plugin produces a plain Kotlin object

The Kotlin DSL configuration declares the plugin, sets a package name and puts the values into a `defaultConfigs` block.

```kotlin
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.20")
        classpath("com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:latest_version")
    }
}

plugins {
    kotlin("multiplatform")
    id("com.codingfeline.buildkonfig")
}

buildkonfig {
    packageName = "com.example.app"

    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }
}
```

The Groovy DSL is documented in parallel, with `apply plugin:` instead of the `plugins` block and single quoted arguments. Generation happens through the `generateBuildKonfig` task, which also runs automatically whenever a Kotlin compile task executes, so a normal build produces the file without a separate step. The output for the configuration above is an internal object in commonMain holding a single string constant.

## targetConfigs make the generated object expect and actual

Values that differ per platform go into `targetConfigs`, where each block is named after the target you declared in the Kotlin block. The same name can be reused across the default and the target blocks, and the target value overwrites the default one. The Kotlin DSL shows both a nullable field and a target that changes the value of a common field.

```kotlin
buildkonfig {
    packageName = "com.example.app"

    // default config is required
    defaultConfigs {
        buildConfigField(STRING, "name", "value")
    }

    targetConfigs {
        // names in create should be the same as target names you specified
        create("android") {
            buildConfigField(STRING, "name2", "value2")
            buildConfigField(STRING, "nullableField", "NonNull-value", nullable = true)
        }

        create("ios") {
            buildConfigField(STRING, "name", "valueForNative")
        }
    }
}
```

The documentation notes that when target configs are present the generated code is emitted as `expect` and `actual`, since a single commonMain object cannot hold a value that differs per target. The Groovy form uses the target name directly as a method rather than a `create` call, which is the one real syntax difference between the two DSLs.

## Four settings, and one of them fails quietly

The surface is small. `packageName` sets where the generated object lives and is required. `objectName` sets the name of the generated object and defaults to `BuildKonfig`. `exposeObjectWithName` sets the name and makes the object public, which is what you need if another module has to read it. `defaultConfigs` holds the values common to every target. The failure mode is the part to notice: if `defaultConfigs` is omitted, a warning is logged and code generation is skipped. Nothing fails, nothing breaks loudly, and the next compile reports a missing symbol. The field function itself comes in two forms, one taking type, name and value, and one that also accepts `nullable` and `const` flags, which is how you declare a nullable field with a non-null fallback value as the example above does.

## Product flavors and multiplatform hierarchies are listed but not explained

The table of contents of the documentation lists three further topics beyond the core configuration: a section on product flavors, a section on overwriting values, and a section on HMPP, the hierarchical multiplatform project structure. Those sections are the first place to look before adopting the plugin in a project whose build is more complex than a flat list of targets.

## Two modules, two samples and a release cadence you can follow

The repository is split into two modules, `buildkonfig-compiler` and `buildkonfig-gradle-plugin`, which matches the split between the code generation and the Gradle integration, and it ships two example projects, `sample` and `sample-kts`, so you can see a working configuration in both DSL styles. Alongside the code there is a CHANGELOG.md, a RELEASING.md and a release-please configuration, which explains how the version numbers are produced, and a renovate.json for dependency updates. Releases are tagged as v0.23.0 on 2026-09-19, v0.22.0 on 2026-06-24 and v0.21.2 on 2026-05-20. The last push was on 2026-10-15 and the licence is Apache-2.0. The version numbers are still below one, which tells you the API surface is expected to move.

## Conclusion

Use BuildKonfig when a Kotlin Multiplatform project has the same handful of endpoints, keys or flags to express on more than one platform, since it replaces two separate build config mechanisms with one generated object. Leave it out if your project already has a working answer, because the plugin adds a compile step and pins you to recent Kotlin and Gradle versions, and the version requirement alone will rule out older builds. Before you rely on it, run the generateBuildKonfig task once on a scratch configuration, because omitting defaultConfigs produces a warning and skips code generation rather than failing loudly.

## FAQ

### What does the BuildKonfig Gradle plugin do?

It generates a Kotlin object holding build time values that you declare in Gradle, so the same constants can be read from shared code in a Kotlin Multiplatform or Kotlin/JVM project instead of being wired separately into each platform's build configuration.

### What are the requirements for using BuildKonfig?

Kotlin 2.4.20 or later, the Kotlin Multiplatform or Kotlin/JVM plugin applied to the project, and Gradle 8.14 or later. The plugin depends on the Kotlin Gradle Plugin 2.4.20, so declaring an older Kotlin version resolves to 2.4.20 anyway.

### How do I set a value that differs per platform?

Use a `targetConfigs` block and name each block after the target you declared in the Kotlin block. When target configs are present, the generated code is emitted as expect and actual, and a target value overwrites the default value for the same field name.

### What happens if I forget the defaultConfigs block?

The documentation says a warning is logged and code generation is skipped, so the build does not stop with a clear error and the missing object shows up later as a compile error.

## Sources

- [Issues](https://github.com/yshrsmz/BuildKonfig/issues)
- [License: Apache-2.0](https://github.com/yshrsmz/BuildKonfig/blob/master/LICENSE)
- [README](https://github.com/yshrsmz/BuildKonfig/blob/master/README.md)
- [Releases](https://github.com/yshrsmz/BuildKonfig/releases)
- [yshrsmz/BuildKonfig on GitHub](https://github.com/yshrsmz/BuildKonfig)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yshrsmz-buildkonfig
