Kotlin Knowledge Patch
Use this skill when writing, reviewing, upgrading, or troubleshooting Kotlin source, builds, multiplatform targets, Compose Multiplatform applications, or the Kotlin ecosystem. Start with the migration checks below, then open only the reference files relevant to the task.
Reference index
| Reference | Topics |
|---|---|
| language-and-compiler.md | Language semantics, context parameters, diagnostics, annotations, JVM interop, reflection, and scripting |
| jvm-and-build-tooling.md | Gradle and Maven compatibility, KGP APIs, kapt, publishing, ABI validation, and the Build Tools API |
| multiplatform-and-native.md | Multiplatform source sets, Apple targets, Kotlin/Native, C/Objective-C interop, and Swift export |
| javascript-and-wasm.md | Kotlin/JS, Kotlin/Wasm, JavaScript interop, browser and Node tooling, and NPM publishing |
| standard-library.md | Time, UUIDs, atomics, arrays, collections, and removed APIs |
| compose-multiplatform.md | Compose compiler changes, resources, navigation, iOS, web, desktop, previews, and testing |
| ecosystem-libraries.md | Coroutines, serialization, Ktor, Exposed, Koog, IDE, and editor tooling |
Upgrade triage
Before changing source, identify the exact Kotlin, Kotlin Gradle plugin, Gradle, Android Gradle plugin, Compose Multiplatform, and ecosystem-library versions. Patch releases repair compiler, reflection, JavaScript, Native, Wasm, scripting, and Compose regressions, so check whether a patch upgrade is the actual fix.
For build upgrades:
- Remove obsolete Gradle properties and compiler flags before diagnosing new failures.
- Compare common and platform dependency resolution separately in multiplatform builds.
- Move custom plugins from removed KGP internals and mutable extension assignments to supported APIs.
- Clean Native commonization caches after removing obsolete number-commonization properties.
- Re-run ABI validation, Compose mapping generation, JavaScript/Wasm tests, and Native link tasks.
Breaking language and compiler changes
Replace context receivers with context parameters
Context receivers are removed. Rewrite declarations with named context parameters:
context(logger: Logger)
fun report(message: String) = logger.log(message)
Context parameters are valid only on functions and whole properties. Contextual properties require accessors and cannot have backing fields, initializers, or delegates. Use _ for a value that participates in resolution but is not referenced by name.
A call requires exactly one compatible value at the nearest scope level. Same-level matches are ambiguous, and an overload with context parameters is not more specific than a matching overload without them. Callable references capture their context when created.
Account for stricter source checks
Expect errors for inaccessible types exposed through indirect dependencies, less-visible type-parameter bounds, private references from non-private inline declarations, nullable type-alias supertypes, serializable inline lambdas, invalid generic Java delegation, and several variance-bearing type-alias uses.
Kotlin 2.3.21 postponed strict rejection of inferred type arguments that violate upper bounds. Do not use that patch as proof that source satisfies the future restriction.
Migrate removed language and library forms
- Do not use callable references to Java synthetic properties; call Java accessors directly.
- Replace
kotlin.native.Throwswithkotlin.Throws. - Replace
AbstractDoubleTimeSourcewithAbstractLongTimeSource. - Replace old character and number conversion APIs and
Number.toChar()with explicit conversions. - Use
kotlin.io.path.createTempDirectoryandcreateTempFileinstead of the removedkotlin.ioforms. - Give
String.subSequencearguments the currentstartIndexandendIndexnames. - Do not place a non-local
returnin a default lambda.
Use current JVM defaults and annotations
Use stable -jvm-default; its default mode is enable. Select no-compatibility to emit only interface defaults or disable for the legacy DefaultImpls-only scheme.
Use @JvmExposeBoxed or -Xjvm-expose-boxed when Java callers need boxed entry points for inline value classes. Use @all:Ann with -Xannotation-target-all when an annotation must propagate to every applicable property-related target.
Annotated JVM lambdas use invokedynamic by default, so reflection must not assume annotations exist on a generated lambda class.
Adopt opt-in features deliberately
- Enable
-Xexplicit-backing-fieldswhen a public property's backing storage needs a narrower implementation type. - Enable
-Xreturn-value-checker=checkorfull, then use@MustUseReturnValues,@IgnorableReturnValue, orval _ = call()to express intent. - Use name-based destructuring only behind
-Xname-based-destructuring; its modes intentionally differ in syntax and compatibility behavior. - Use per-diagnostic
-Xwarning-level=NAME:error|warning|disabledwhen global warning settings are too broad. - Treat direct C/Objective-C calls, reified catches, expanded contracts, and JavaScript interface implementation as experimental.
Gradle, Android, and compiler tooling
Migrate Android builds for AGP 9
AGP 9 has built-in Kotlin support. Stop applying org.jetbrains.kotlin.android. For multiplatform Android libraries, apply com.android.kotlin.multiplatform.library and replace androidTarget {} with android {}. Keep androidTarget only on an older AGP line where it remains valid.
Compose Multiplatform projects should normally isolate the Android application in its own module. Confirm the exact Compose release before combining it with AGP 9.
Use current Kotlin Gradle plugin APIs
- Register generated Kotlin through
KotlinSourceSet.generatedKotlin; readallKotlinSourceswhen generated sources must be included. - Use
source()to add compile inputs;KotlinCompileTool.setSource()now replaces them. - Configure generated resources through
KotlinSourceSet.resources. - Use
compilerOptions, not legacykotlinOptionsproperties. - Configure JS and Wasm runtimes through
*EnvSpecGradle properties. - Use Gradle's
ExtraPropertiesExtension, not internalExtrasProperty. - Configure Kotlin dependencies on
KotlinSourceSet, notHasKotlinDependencieshelpers.
Do not subclass Kotlin test, JavaScript runtime, webpack, Karma, or Yarn setup classes. Configure them through supported plugin DSLs.
Expect Build Tools API defaults
Kotlin/JVM Gradle compilation uses the Build Tools API by default. The API supports immutable built operations, best-effort cancellation, common metrics, and structured compiler-plugin configuration. The deprecated out-of-process execution strategy is unsupported; use daemon or in-process compilation.
When the Kotlin Maven plugin is a build extension, it can register standard Kotlin source roots and add kotlin-stdlib automatically. Disable both with kotlin.smart.defaults.enabled=false only when explicit control is required.
Update kapt and ABI validation
K2 kapt is the default. If a regression cannot yet be avoided, temporarily set kapt.use.k2=false. Use typed annotationProcessorOptionsProviders and add providers with addAll().
Use checkKotlinAbi and updateKotlinAbi; ABI validation wires its check into Gradle's check lifecycle. Older task aliases remain temporarily available.
Multiplatform and Native
Use concrete targets and current source-set defaults
Replace removed ios(), watchos(), and tvos() shortcuts with concrete targets. The default hierarchy creates webMain and webTest above JS and Wasm when both targets are declared. Cross-host KLIB publication does not remove the need for macOS when cinterop, CocoaPods, final Apple binaries, or Apple tests are involved.
Multiplatform metadata matching is stricter. If metadata compilation fails after an upgrade, compare resolved dependencies in common and platform source sets before changing compiler code.
Treat Apple baselines as deployment constraints
Native deployment baselines are iOS/tvOS 14 and watchOS 7. Apple x86-64 targets are tier 3. Overrides requesting older deployment versions are unsupported and can fail during the build or at runtime.
KDoc export and Objective-C block parameter names are enabled by default. Disable them only for a concrete compatibility need.
Configure Swift export explicitly
Use swiftExport to name modules, flatten package prefixes, export dependencies, and pass compiler arguments. Put dependency-required opt-ins in the Kotlin module's compilerOptions, not inside an export block. Review declaration-shape limits before designing a Swift-facing API.
Do not publish libraries built with experimental direct C/Objective-C call mode.
JavaScript and Wasm
Separate JS and Wasm tooling
Wasm build files live under build/wasm and use Wasm-specific install, package, environment, D8, and Binaryen APIs. Replace removed task aliases with explicit browser or Node development-run and production-distribution tasks.
Kotlin/Wasm initializes during module instantiation. Avoid @EagerInitialization where it could run before initialization completes.
Choose interop flags intentionally
-Xes-long-as-bigintmapsLongto JavaScriptBigIntandLongArraytoBigInt64Array.-Xenable-suspend-function-exportingexposes exported suspend APIs as JavaScript promises.-Xenable-implementing-interfaces-from-typescriptlets generated TypeScript implementations identify Kotlin interfaces by symbol.@nativeInvokeenables direct calls to callable external JavaScript objects on Wasm.@JsExport.Defaultcreates ES-module default exports.
Deploy Wasm browser applications only where WebAssembly garbage collection and the required exception-handling behavior are supported. Use the combined JS/Wasm browser distribution when a JavaScript fallback is required.
Standard library highlights
kotlin.time.Clock and kotlin.time.Instant are stable. UUID parsing accepts dashed and plain hexadecimal forms; newer experimental APIs add nullable parsers plus v4 and v7 generation.
Common atomics support functional updates that return the old value, the new value, or no value. Array copyOf(newSize) { initializer } fills new slots without widening Array<T> to Array<T?>.
Iterable.intersect() and subtract() now apply ordinary Any.equals membership consistently, including when the supplied collection uses referential equality internally.
Compose Multiplatform essentials
Use direct library coordinates instead of deprecated Compose Gradle-plugin dependency aliases. Import the unified androidx.compose.ui.tooling.preview.Preview annotation for common previews.
Migrate Java-only resource APIs to the multiplatform resource library. Android library targets may need androidResources.enable = true; XCFramework resource embedding requires a current Kotlin Gradle plugin.
On iOS, set CADisableMinimumFrameDurationOnPhone to true. Concurrent rendering is enabled by default in 1.11, native interop can be placed as overlays, and the newer text-input path remains opt-in.
On web, prefer ComposeViewport, WebElementView, and NavController.bindToBrowserNavigation(). Accessibility is enabled by default. CanvasBasedWindow and Window.bindToNavigation() are deprecated.
Compose UI testing now favors the v2 runner with StandardTestDispatcher. Delayed composition coroutines can count as idle, so advance the test clock explicitly when delayed work matters.
Ecosystem checks
Coroutines add Flow.any, all, none, and chunked; runTest has a 60-second default whole-test timeout. Close dispatcher views with use when their backing dispatcher is closeable.
Serialization adds stable JSON leniency options, per-class unknown-key handling, standard Instant serializers, sealed-subclass registration, CBOR/COSE options, generated-serializer retention, UUID support, kotlinx-io integration, and ProtoBuf oneof hierarchies. Match the serialization runtime and compiler-plugin requirements in the reference.
Ktor, Exposed, Koog, Kotlin language-server tooling, and editor support have substantial newer capabilities; inspect the ecosystem reference before selecting APIs or assuming lifecycle status.