Kotlin Multiplatform (KMP) dejó de ser un experimento en noviembre de 2023, cuando JetBrains anunció la estabilidad del target de iOS. Desde entonces la tecnología lleva año y medio ganando terreno en equipos que ya usan Kotlin para Android y no quieren mantener dos bases de código paralelas. En 2026 el soporte en Android Studio es nativo, empresas como Netflix o McDonald's lo usan en producción y el wizard de IntelliJ levanta un proyecto KMP en dos clics. Este artículo explica cómo funciona, qué puedes compartir, qué herramientas necesitas y cómo se compara con las alternativas.
Qué comparte KMP y qué no
La idea central de KMP es sencilla: escribe una vez la lógica que no tiene nada que ver con la pantalla y compílala para cada plataforma. Lo que se comparte habitualmente son los modelos de datos, las llamadas de red, la capa de caché local y cualquier lógica de negocio pura. Lo que normalmente no se comparte es la interfaz de usuario, aunque eso también ha cambiado con Compose Multiplatform.
Las plataformas que puedes cubrir desde un solo repositorio son Android, iOS, desktop (JVM), web con Kotlin/Wasm y web con Kotlin/JS. No tienes que apuntar a todas a la vez: puedes empezar solo con Android e iOS y añadir más targets después sin tocar el código común.
El mecanismo expect / actual
Cuando una API difiere entre plataformas, KMP usa un contrato llamado expect/actual. En el módulo compartido declaras lo que esperas:
expect fun platformName(): String
Y en cada módulo de plataforma pones la implementación real:
// androidMain
actual fun platformName(): String = "Android ${Build.VERSION.SDK_INT}"
// iosMain
actual fun platformName(): String = UIDevice.currentDevice.systemName()
El compilador comprueba que cada plataforma tenga su actual correspondiente. Si falta alguna, falla en tiempo de compilación, no en ejecución. Esto cubre desde algo tan simple como el nombre de la plataforma hasta wrappers sobre APIs de sistema como notificaciones, permisos o cifrado.
Estructura de un proyecto KMP
Un proyecto KMP típico organiza el código en source sets. El más importante es commonMain, que contiene todo lo que se comparte. Luego están los específicos de plataforma: androidMain, iosMain, jvmMain, jsMain o wasmMain según lo que necesites. Para los tests tienes commonTest, que se ejecuta en todas las plataformas configuradas.
La configuración va en build.gradle.kts dentro del bloque kotlin:
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:2.3.9")
implementation("app.cash.sqldelight:runtime:2.0.1")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-okhttp:2.3.9")
implementation("app.cash.sqldelight:android-driver:2.0.1")
}
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.9")
implementation("app.cash.sqldelight:native-driver:2.0.1")
}
}
}
}
Ktor para llamadas de red
Ktor es el cliente HTTP de JetBrains y es completamente multiplataforma. El código que defines en commonMain para hacer una petición funciona igual en Android, iOS y desktop; lo que cambia es el motor que usa por debajo.
val client = HttpClient {
install(ContentNegotiation) {
json()
}
}
val response: MyData = client.get("https://api.ejemplo.com/datos").body()
En Android el motor es OkHttp, que ya conoces si llevas tiempo en el stack Android. En iOS usa Darwin, que se apoya en NSURLSession. En JVM server-side puedes usar CIO. Cambias el motor añadiendo la dependencia correcta en el source set de cada plataforma; el código de red que está en commonMain no se toca.
SQLDelight: base de datos sin duplicar esquemas
SQLDelight resuelve el problema de la persistencia local de una forma bastante directa. Defines el esquema y las queries en archivos .sq con SQL estándar:
-- Usuario.sq
CREATE TABLE Usuario (
id INTEGER NOT NULL PRIMARY KEY,
nombre TEXT NOT NULL,
email TEXT NOT NULL
);
selectAll:
SELECT * FROM Usuario;
insertar:
INSERT INTO Usuario(id, nombre, email) VALUES (?, ?, ?);
El plugin de Gradle genera a partir de ahí código Kotlin con tipos seguros para todas las plataformas. Luego instancias la base de datos con el driver nativo de cada entorno:
// Android
val driver = AndroidSqliteDriver(Database.Schema, context, "app.db")
// iOS (Kotlin/Native)
val driver = NativeSqliteDriver(Database.Schema, "app.db")
El resultado es que la lógica que lee o escribe datos vive en commonMain y no sabe nada del driver. Los drivers son detalles de cada plataforma.
Compose Multiplatform: la UI también puede compartirse
KMP en principio no obliga a compartir la UI. Puedes usar SwiftUI en iOS y Jetpack Compose en Android con toda la lógica compartida por debajo, que es la opción más conservadora y la que más control te da sobre la experiencia nativa de cada plataforma.
Pero si quieres ir más lejos, JetBrains mantiene Compose Multiplatform, que extiende Jetpack Compose a otras plataformas. El soporte para Android y desktop (Windows, macOS, Linux) lleva tiempo siendo estable. iOS alcanzó la estabilidad con Compose Multiplatform 1.6 en 2024. La versión web con Kotlin/Wasm sigue siendo experimental en 2026, aunque avanza bastante rápido.
Para proyectos nuevos donde el equipo ya domina Compose y quiere máxima reutilización, combinar KMP con Compose Multiplatform tiene mucho sentido. Para proyectos donde la experiencia nativa en iOS es prioritaria, lo habitual es mantener SwiftUI y solo compartir la capa de datos.
KMP vs Flutter vs React Native
La pregunta sale siempre, así que vale la pena ser directo al respecto.
- Flutter comparte todo, incluyendo la UI, con Dart. Está muy maduro, tiene buena performance y un ecosistema amplio. El inconveniente es que introduces Dart en un equipo que probablemente ya trabaja con Kotlin y Swift.
- React Native usa JavaScript o TypeScript, lo que puede ser una ventaja si tu equipo viene del frontend web. El bridge con las APIs nativas ha mejorado mucho con JSI, pero sigue siendo un intermediario entre tu código y la plataforma.
- KMP no impone una UI compartida. Puedes usarla o no. Si tu equipo Android ya trabaja con Kotlin, la curva de entrada es mínima. El código compartido compila a código nativo en iOS (a través de Kotlin/Native), sin bridge de por medio.
En 2026 KMP está ganando terreno sobre todo en empresas con equipos Android consolidados que quieren cubrir iOS sin montar un equipo Swift desde cero. No es la bala de plata para todo, pero para ese caso concreto encaja bien.
Si quieres entender mejor la evolución del lenguaje que hay debajo, puedes leer sobre Kotlin y su evolución hacia el desarrollo multiplataforma o sobre Kotlin en Android: base del KMP moderno.
Tooling y adopción en 2026
Android Studio incluye soporte nativo de KMP con el plugin oficial de Kotlin Multiplatform. Fleet, el IDE de JetBrains, está diseñado desde el principio para proyectos que mezclan targets y tiene una vista unificada de todos los source sets. El wizard de creación de proyectos en IntelliJ y Android Studio genera la estructura básica con los módulos ya configurados sin necesidad de tocar manualmente el Gradle.
En producción ya hay nombres conocidos: Netflix usa KMP para compartir lógica de reproducción, VMware para herramientas internas, Philips en aplicaciones médicas. No son proyectos pequeños ni experimentos de laboratorio.
La documentación oficial en kotlinlang.org está actualizada y tiene tutoriales paso a paso para los casos más habituales, incluyendo la integración con CocoaPods en iOS si necesitas consumir librerías nativas de Swift.
Imagen: Pexels / cottonbro studio
