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.
76
93%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Turn "the iOS build is slow" into a measured diagnosis and a small set of safe fixes. Two rules apply throughout:
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 |
| Kotlin/Native compiler distribution downloaded on every CI run | ~/.konan not preserved between runs | caching-and-gradle |
| Long pause before the first task starts | Configuration phase, no configuration cache | caching-and-gradle |
| All iOS targets build when only one simulator is needed | Broad task (build, assemble, assemble*XCFramework) or unused targets | artifacts-and-targets |
ksp* tasks ahead of compileKotlinIos* | Generated-code work on the native path | exports-and-generated-code |
| Small source edit recompiles and relinks everything | Compiler caches disabled, or missing incrementality | caching-and-gradle, experimental |
Machine overloaded while several link* tasks run at once | Parallel native linking | caching-and-gradle, worker-limit caveat |
Run the static audit from the project root:
scripts/audit-native-build.sh /path/to/projectIt 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.
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.
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.
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.
Apply fixes one at a time, re-measuring as you go:
~/.konan warm in CI, update
Kotlin: references/caching-and-gradle.mdtransitiveExport, narrow
export(...), scope KSP work to the native compilations that need it:
references/exports-and-generated-code.mdA 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 64sReasoning chain:
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)iosX64 work serves Intel simulators; ask whether the team still
supports them before removing the target. (artifacts-and-targets)org.gradle.configuration-cache=true once trialed. (caching-and-gradle)assembleXCFramework untouched; note that explicitly in the
report.linkRelease*,
*ReleaseXCFramework, or removed generator tasks.scripts/audit-native-build.sh reports no findings you have not
consciously accepted and documented.Close with a short performance note:
| Topic | Link |
|---|---|
| Improving Kotlin/Native compilation time | https://kotlinlang.org/docs/native-improving-compilation-time.html |
| Kotlin Gradle plugin compilation and caches | https://kotlinlang.org/docs/gradle-compilation-and-caches.html |
| iOS integration methods | https://kotlinlang.org/docs/multiplatform-ios-integration-overview.html |
| Direct integration with Xcode | https://kotlinlang.org/docs/multiplatform/multiplatform-direct-integration.html |
| Building final native binaries and XCFrameworks | https://kotlinlang.org/docs/multiplatform/multiplatform-build-native-binaries.html |
| Kotlin/Native binary options | https://kotlinlang.org/docs/native-binary-options.html |
| KSP with Kotlin Multiplatform | https://kotlinlang.org/docs/ksp-multiplatform.html |
c2f9069
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.