Last updated: March 20, 2026


layout: default title: “Best AI for Writing Correct Kotlin Multiplatform Shared” description: “A practical guide for developers comparing AI tools that help write correct Kotlin Multiplatform shared code modules, with code examples and recommendations.” date: 2026-03-20 author: theluckystrike permalink: /best-ai-for-writing-correct-kotlin-multiplatform-shared-code/ categories: [guides, comparisons] reviewed: true score: 9 intent-checked: true voice-checked: true tags: [ai-tools-compared, artificial-intelligence, kotlin, best-of] —

Kotlin Multiplatform has matured significantly, enabling developers to share code across Android, iOS, web, desktop, and server targets from a single codebase. However, writing correct shared code modules requires careful attention to platform-specific limitations, expect/actual patterns, and compilation targets. In 2026, AI coding assistants have developed varying levels of sophistication for handling these challenges. This guide evaluates which tools best help developers produce correct Kotlin Multiplatform implementations.

Key Takeaways

The @Serializable annotation and Json {} configuration block are well understood by most AI tools.

Understanding Kotlin Multiplatform Correctness Challenges

Writing Kotlin Multiplatform shared code involves more than writing cross-platform Kotlin. Developers must navigate several correctness pitfalls that AI tools can help identify and prevent.

The expect/actual mechanism requires precise matching between expected declarations in the common module and actual implementations in platform-specific modules. Mismatched signatures cause compilation failures that are sometimes difficult to diagnose. Additionally, not all Kotlin standard library functions are available on all platforms, and some require specific dependencies or workarounds.

When sharing code between mobile and backend targets, developers encounter differences in threading models, I/O operations, and available APIs. An AI tool that understands these constraints can suggest appropriate alternatives or flag problematic code before it causes runtime errors.

The kotlinx ecosystem — including kotlinx.coroutines, kotlinx.serialization, and kotlinx.datetime — is essential for KMP development because these libraries are explicitly designed with multiplatform compatibility in mind. AI tools with deep KMP knowledge will reach for these libraries rather than platform-specific equivalents.

Key Capabilities for Kotlin Multiplatform AI Tools

Effective AI assistance for Kotlin Multiplatform requires several specific capabilities. First, the tool must recognize the expect/actual pattern and verify that actual implementations correctly satisfy expected declarations. Second, it should understand which APIs are available on which platforms and warn when platform-specific code appears in common modules. Third, the tool should suggest appropriate platform-specific implementations when writing expect declarations.

Context awareness matters significantly. A tool that understands the project’s build configuration, target platforms, and dependencies can provide more relevant suggestions than one working with limited visibility into the project structure.

Gradle configuration is another area where AI tools diverge. The build.gradle.kts files for KMP projects are complex, involving multiple source sets, target declarations, and dependency scoping. An AI that can generate or diagnose correct Gradle configurations saves significant setup time.

Code Example: Expect/Actual Pattern

Consider a common module that expects a platform-specific UUID generator:

// commonMain
expect class UUIDGenerator() {
    fun generate(): String
}

// androidMain
actual class UUIDGenerator {
    actual fun generate(): String {
        return java.util.UUID.randomUUID().toString()
    }
}

// iosMain
actual class UUIDGenerator {
    actual fun generate(): String {
        return NSUUID().UUIDString()
    }
}

An effective AI assistant should recognize this pattern, verify that actual implementations match expected signatures, and suggest appropriate implementations for each platform. It should also flag cases where a developer accidentally writes platform-specific imports in common code.

Tool Comparison: AI Assistants for Kotlin Multiplatform

Different AI coding assistants demonstrate varying levels of Kotlin Multiplatform expertise. Here is how the major tools perform across critical dimensions:

Tool Expect/Actual Accuracy KMP Gradle Config kotlinx Library Suggestions Platform API Warnings Overall KMP Score
Claude 3.7 Sonnet Excellent Very Good Excellent Good 9/10
GitHub Copilot Good Good Good Fair 7/10
Cursor (GPT-4o) Good Good Good Fair 7/10
Gemini 1.5 Pro Fair Fair Good Fair 6/10
Tabnine Limited Limited Limited Poor 4/10

Claude 3.7 Sonnet consistently generates expect/actual declarations with matching signatures and reaches for kotlinx.datetime and kotlinx.coroutines as first choices rather than platform-specific alternatives. GitHub Copilot and Cursor perform well for common patterns but occasionally suggest platform-specific APIs in common source sets. Tabnine’s autocomplete-only model struggles with the multi-file, multi-module context required for KMP.

Code Example: Platform-Specific API Handling

A common challenge involves using platform-specific APIs in shared code:

// This code in commonMain will fail on some platforms
fun getTimestamp(): Long {
    return System.currentTimeMillis() // Not available on all platforms
}

An AI tool aware of Kotlin Multiplatform should suggest using kotlinx.datetime or a custom expect/actual implementation:

// commonMain
import kotlinx.datetime.Clock

fun getTimestamp(): Long {
    return Clock.System.now().toEpochMilliseconds()
}

For cases where no cross-platform library exists, the AI should scaffold the expect/actual boilerplate:

// commonMain
expect fun getTimestamp(): Long

// androidMain
actual fun getTimestamp(): Long {
    return System.currentTimeMillis()
}

// iosMain
actual fun getTimestamp(): Long {
    return (NSDate().timeIntervalSince1970 * 1000).toLong()
}

Tools that recognize the kotlinx.datetime library or similar cross-platform solutions provide more practical guidance than those that simply flag errors without offering solutions.

Real-World Workflow: Setting Up a KMP Shared Module

Here is a realistic workflow for creating a shared networking module using Ktor — the KMP-native HTTP client — and how AI tools assist at each stage.

Step 1: Define the build.gradle.kts configuration

kotlin {
    androidTarget {
        compilations.all {
            kotlinOptions.jvmTarget = "1.8"
        }
    }
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:2.3.8")
                implementation("io.ktor:ktor-client-content-negotiation:2.3.8")
                implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.8")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:2.3.8")
            }
        }
        val iosMain by creating {
            dependencies {
                implementation("io.ktor:ktor-client-darwin:2.3.8")
            }
        }
    }
}

Claude generates this configuration correctly on the first attempt, including the engine-specific dependencies for each platform. Copilot requires a prompt that specifies Ktor versions explicitly to avoid suggesting outdated dependency coordinates.

Step 2: Write the shared API client

// commonMain
class ApiClient(private val httpClient: HttpClient) {
    suspend fun fetchUser(userId: String): User {
        return httpClient.get("https://api.example.com/users/$userId").body()
    }
}

Step 3: Provide the engine via expect/actual

// commonMain
expect fun createHttpClient(): HttpClient

// androidMain
actual fun createHttpClient(): HttpClient = HttpClient(Android) {
    install(ContentNegotiation) {
        json()
    }
}

// iosMain
actual fun createHttpClient(): HttpClient = HttpClient(Darwin) {
    install(ContentNegotiation) {
        json()
    }
}

AI tools that understand Ktor’s multiplatform architecture generate this pattern correctly. Those that lack KMP training may suggest the OkHttp engine in common code, which fails on iOS.

Specific Use Cases and Limitations

Use case: Shared business logic with coroutines

AI tools handle kotlinx.coroutines well in KMP context, including CoroutineScope management and Dispatchers.IO versus Dispatchers.Default for CPU versus I/O bound work. Claude correctly warns when developers use Dispatchers.Main in common code without importing the proper common coroutines artifact.

Use case: Serialization with kotlinx.serialization

The @Serializable annotation and Json {} configuration block are well understood by most AI tools. Where tools diverge is in edge cases like polymorphic serialization and custom serializers for platform-specific types.

Use case: Shared ViewModels or Presentation Layer

Some teams share ViewModels using the moko-mvvm library or KMP-NativeCoroutines for Swift interop. This is an area where AI tools often struggle, as the patterns are less represented in training data. Prompting with explicit library names and versions yields better results.

Limitations to be aware of:

Best Practices for Working with AI on Kotlin Multiplatform

To get the best results from AI coding assistants when writing Kotlin Multiplatform code, provide clear context about your target platforms. Specify whether you’re targeting Android, iOS, web, desktop, or server, and mention any relevant dependencies in your prompts.

When requesting help with expect/actual patterns, include both the expected declaration and the target platform in your request. This helps the AI generate more accurate actual implementations.

Always review AI-generated code for platform compatibility. Even sophisticated tools may occasionally suggest APIs that aren’t available on all targets. Building and testing on all target platforms remains essential, even when using AI assistance.

Include your build.gradle.kts source sets section in the prompt context. The AI’s suggestions improve dramatically when it knows exactly which targets your module supports.

FAQ

Q: Which AI tool handles expect/actual declaration generation most reliably?

Claude 3.7 Sonnet generates correct expect/actual pairs most consistently, particularly for complex patterns like expected interfaces with multiple implementations. GitHub Copilot is a close second for common patterns but occasionally drops the actual modifier or mismatches parameter types.

Q: Can AI tools generate correct KMP Gradle configurations from scratch?

Yes, with specific prompting. Provide the list of targets you need (e.g., androidTarget, iosArm64, jvm, js), the libraries you want to use, and the Kotlin version. Claude and Copilot both produce buildable Gradle configurations for straightforward setups. More complex configurations with custom source set hierarchies may require manual adjustment.

Q: How do I prevent AI from suggesting JVM-only APIs in common code?

Add explicit instructions in your system prompt or comment context: “This file is in the commonMain source set. Do not suggest any platform-specific APIs including java., android., or UIKit.” Most AI tools respect this constraint when it is explicitly stated.

Q: Is Compose Multiplatform supported in AI training data?

Partially. Compose Multiplatform has stabilized on desktop and is in beta on iOS. AI tools have reasonable coverage of standard composables but may suggest Android-specific Compose APIs (like LocalContext.current) in multiplatform contexts where they fail on iOS.

Advanced: Custom AI Instructions for KMP Projects

Set up system prompts that teach AI tools your project’s KMP conventions. Include this in your IDE settings or commit to the repository:

# KMP Development Context

You are assisting with Kotlin Multiplatform Mobile development.

## Key Rules
1. Common module code must NOT reference platform-specific packages (java.*, android.*, UIKit)
2. Use kotlinx libraries as first choice: kotlinx.coroutines, kotlinx.datetime, kotlinx.serialization
3. Always verify expect/actual pairs have matching signatures
4. State the target platforms: Android, iOS, Web, Desktop, JVM
5. For I/O operations, use Ktor client (engine per platform via expect/actual)
6. For date/time, use kotlinx.datetime.Clock (never System.currentTimeMillis in common code)

## Gradle Structure to Understand
- commonMain: Shared code (NO platform-specific imports)
- androidMain: Android-specific implementations
- iosMain/iosX64/iosArm64: iOS targets (each is a separate target, not just variants)
- desktopMain/jsMain/jvmMain: Other platforms

## Example Patterns
- Expect/actual for platform APIs
- Sealed classes for platform-specific behavior
- Extension functions for common operations
- Coroutines for async work across all platforms

Adding this context to your Claude/Copilot system prompt reduces errors significantly.

CLI Workflow for Validating KMP Builds

Automate validation of KMP correctness across all platforms. This bash script catches type mismatches and missing implementations:

#!/bin/bash
# Validate KMP builds across all targets

set -e

echo "Building commonMain..."
./gradlew compileCommonMainKotlinMetadata

echo "Building Android..."
./gradlew assembleDebug

echo "Building iOS..."
./gradlew iosX64MainKlibrary

echo "Building JVM..."
./gradlew jvmMainKlibrary

echo "Building JavaScript..."
./gradlew jsMainKlibrary

echo "All platforms compiled successfully!"

Use this in your pre-push hook to catch platform-specific errors before pushing:

# .git/hooks/pre-push
#!/bin/bash
./scripts/validate-kmp.sh || exit 1

Decision Framework for Platform-Specific Code

When facing a choice between common code, expect/actual, and platform-specific modules, follow this flowchart:

Does the code need platform-specific APIs?
├─ No → Keep in commonMain
└─ Yes → Use expect/actual?
    ├─ If multiple implementations → expect/actual in commonMain
    ├─ If single platform → Platform-specific sourceSet
    └─ If complex logic → Sealed class in commonMain with platform subclasses

Practical examples:

// Option 1: Expect/actual (best for simple cases)
// commonMain
expect fun getSystemLanguage(): String

// androidMain
actual fun getSystemLanguage(): String = Locale.getDefault().language

// iosMain
actual fun getSystemLanguage(): String = NSLocale.currentLocale.languageCode

// Option 2: Sealed class (best for complex platform logic)
// commonMain
sealed class PlatformConfig {
    abstract fun getCacheDir(): String
}

expect fun getPlatformConfig(): PlatformConfig

// androidMain
actual fun getPlatformConfig(): PlatformConfig = object : PlatformConfig() {
    override fun getCacheDir(): String = context.cacheDir.absolutePath
}

Testing Kotlin Multiplatform Code with AI Assistance

When asking AI to generate KMP tests, be specific about platform targets:

// Prompt to AI:
// "Generate unit tests for this function that work across all KMP targets: Android, iOS, and JVM.
// Use common test assertions that don't require platform-specific testing libraries.
// Test cases: normal input, empty string, null pointer where applicable."

@Test
fun testProcessUserEmpty() {
    val result = processUser("")
    assertEquals("", result)
}

@Test
fun testProcessUserNormal() {
    val result = processUser("john-doe")
    assertTrue(result.isNotEmpty())
}

For expect/actual testing, generate platform-specific test implementations:

// commonTest
expect fun createTestHttpClient(): HttpClient

// androidTest
actual fun createTestHttpClient(): HttpClient = HttpClient(Mock) {
    engine {
        addHandler { request ->
            respond("test-response", HttpStatusCode.OK)
        }
    }
}

// iosTest
actual fun createTestHttpClient(): HttpClient = HttpClient(Mock) {
    engine {
        addHandler { request ->
            respond("test-response", HttpStatusCode.OK)
        }
    }
}

Troubleshooting Common AI Mistakes on KMP

Watch for these patterns where AI tools commonly stumble:

  1. Missing actual modifier — AI suggests implementation without actual keyword
  2. Platform-specific imports in common code — AI forgets android.* isn’t available everywhere
  3. Outdated KMM APIs — AI suggests deprecated KMM patterns instead of new KMP
  4. Generic type erasure issues — AI generates code that won’t work with Swift interop
  5. Incorrect Gradle syntax — AI suggests old android() target instead of androidTarget()

When pasting code to AI, include the comment: // This is in commonMain source set to trigger better suggestions.

Built by theluckystrike — More at zovo.one