Skip to content

/kotlin-tooling-native-build-performance

Diagnoses and fixes slow Kotlin/Native compilation and linking in Kotlin Multiplatform projects that target iOS. Use when the user reports slow iOS or shared-framework builds, long linkDebug*/linkRelease* or XCFramework tasks, cold CI builds that re-download the Kotlin/Native

From plugin
kotlin-agent-skills
1k10 skills
Install
$ npx -y skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-native-build-performance --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/kotlin-tooling-native-build-performance

Context preview

The summary Claude sees to decide when to auto-load this skill.

Diagnoses and fixes slow Kotlin/Native compilation and linking in Kotlin Multiplatform projects that target iOS. Use when the user reports slow iOS or shared-framework builds, long linkDebug*/linkRelease* or XCFramework tasks, cold CI builds that re-download the Kotlin/Native

SKILL.md

kotlin-tooling-native-build-performance.SKILL.md
name: kotlin-tooling-native-build-performance
description: >
  Diagnoses and fixes slow Kotlin/Native compilation and linking in Kotlin
  Multiplatform projects that target iOS. Use when the user reports slow iOS or
  shared-framework builds, long linkDebug*/linkRelease* or XCFramework tasks,
  cold CI builds that re-download the Kotlin/Native toolchain, KSP or other
  generated code on the native path, transitiveExport usage, or asks for a
  local-development versus CI build performance plan.
license: Apache-2.0
metadata:
  author: JetBrains
  version: "1.0.0"
  tested_models: "openai/gpt-5.5, openai/gpt-5.4-mini"
  last_eval: "2026-07-06"

Kotlin/Native Build Performance

Turn "the iOS build is slow" into a measured diagnosis and a small set of safe fixes. Two rules apply throughout:

1. Never trade away required release behavior. A faster local loop must not change what CI publishes. 2. Measure before and after with the same command and the same build state. An unmeasured fix is a guess.

Step 0: Classify the Slow Scenario

Establish four facts before editing anything: **where** (local or CI), **what** (debug feedback loop or release/distribution artifact), **state** (first build, clean, warm, or no-op), and **phase** (which tasks dominate the log). Then match the dominant symptom:

| Symptom in the build log | Likely cause | Read | |---|---|---| | `linkRelease*` or `*ReleaseXCFramework` tasks in a local development loop | Building distribution artifacts for development | [artifacts-and-targets](references/artifacts-and-targets.md) | | Kotlin/Native compiler distribution downloaded on every CI run | `~/.konan` not preserved between runs | [caching-and-gradle](references/caching-and-gradle.md) | | Long pause before the first task starts | Configuration phase, no configuration cache | [caching-and-gradle](references/caching-and-gradle.md) | | All iOS targets build when only one simulator is needed | Broad task (`build`, `assemble`, `assemble*XCFramework`) or unused targets | [artifacts-and-targets](references/artifacts-and-targets.md) | | `ksp*` tasks ahead of `compileKotlinIos*` | Generated-code work on the native path | [exports-and-generated-code](references/exports-and-generated-code.md) | | Small source edit recompiles and relinks everything | Compiler caches disabled, or missing incrementality | [caching-and-gradle](references/caching-and-gradle.md), [experimental](references/experimental.md) | | Machine overloaded while several `link*` tasks run at once | Parallel native linking | [caching-and-gradle](references/caching-and-gradle.md), worker-limit caveat |

Step 1: Audit and Measure

1. Run the static audit from the project root:

   scripts/audit-native-build.sh /path/to/project

It is read-only and prints `file:line` findings (disabled caches, broad local tasks, `transitiveExport`, broad KSP configuration, missing CI `.konan` cache), each pointing at the reference file with the fix. Findings are leads, not verdicts — confirm each against project policy. 2. Find the command the user actually waits for: a script, a CI step, or the Gradle invocation inside an Xcode build phase. Optimize that command, not a task you picked yourself. 3. Run it twice when practical. The first build downloads Kotlin/Native components and fills caches; only the second and later runs are representative. Attribute time per task before blaming the compiler:

   kotlin.build.report.output=file   # writes build/reports/kotlin-build/

Gradle's `--scan` or `--profile` work too. 4. If you cannot run the build (no macOS host, no Xcode), analyze logs, build scans, or checked-in metrics instead — and state explicitly that the conclusion is static.

Step 2: Fix in Safe Order

Apply fixes one at a time, re-measuring as you go:

1. **Restore healthy defaults** — remove cache/daemon workarounds, enable Gradle build and configuration caches, keep `~/.konan` warm in CI, update Kotlin: [references/caching-and-gradle.md](references/caching-and-gradle.md) 2. **Build only what the feedback loop needs** — one specific task per loop, correct integration method, justified target matrix: [references/artifacts-and-targets.md](references/artifacts-and-targets.md) 3. **Cut export and generated-code cost** — drop `transitiveExport`, narrow `export(...)`, scope KSP work to the native compilations that need it: [references/exports-and-generated-code.md](references/exports-and-generated-code.md) 4. **Experimental switches last, with the user's agreement**: [references/experimental.md](references/experimental.md)

Worked Example

A developer on an Apple Silicon Mac complains that "every shared-module change costs 12 minutes". Their loop runs `./gradlew :shared:assembleXCFramework`. A build scan of the second (warm) run shows:

:shared:linkReleaseFrameworkIosArm64             348s
:shared:linkReleaseFrameworkIosX64               341s
:shared:compileKotlinIosX64                       96s
:shared:linkDebugFrameworkIosSimulatorArm64       41s
:shared:compileKotlinIosSimulatorArm64            38s
configuration phase                               64s

Reasoning chain:

  • The loop is **local + debug + warm**, but ~690s goes to `linkRelease*` —

release linking is an order of magnitude slower than debug and only CI needs it. Replace the local command with `:shared:linkDebugFrameworkIosSimulatorArm64` (or the Xcode embed task if Xcode drives the build). *(artifacts-and-targets)*

  • All `iosX64` work serves Intel simulators; ask whether the team still

supports them before removing the target. *(artifacts-and-targets)*

  • 64s of configuration on every run disappears behind

`org.gradle.configuration-cache=true` once trialed. *(caching-and-gradle)*

  • Expected loop after the change: ~40s compile + ~40s link on warm builds —

confirm by re-running the new command twice and comparing.

  • CI keeps `assembleXCFra
Read more
Ships withkotlin-agent-skills

A collection of AI agent skills useful for projects using the Kotlin language. Skills are following the Agent Skills standard, see agentskills.io for more information.

Get the whole plugin, auto-invoked

Other skills on kotlin-agent-skills.