Kotlin 2.0 Multiplatform Enterprise Development with KMP, Coroutines,
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
skills listSkill Instructions
name: "moai-lang-kotlin" description: "Kotlin 2.0+ development specialist covering Ktor, coroutines, Compose Multiplatform, and Kotlin-idiomatic patterns. Use when building Kotlin server apps, Android apps, or multiplatform projects." version: 1.0.0 category: "language" modularized: false tags: ['kotlin', 'ktor', 'coroutines', 'compose', 'android', 'multiplatform'] context7-libraries: "/ktorio/ktor, /jetbrains/compose-multiplatform, /jetbrains/exposed" related-skills: "moai-lang-java, moai-lang-swift" updated: 2025-12-07 status: "active"
Quick Reference (30 seconds)
Kotlin 2.0+ Expert - K2 compiler, coroutines, Ktor, Compose Multiplatform with Context7 integration.
Auto-Triggers: Kotlin files (.kt, .kts), Gradle Kotlin DSL (build.gradle.kts, settings.gradle.kts)
Core Capabilities:
- Kotlin 2.0: K2 compiler, coroutines, Flow, sealed classes, value classes
- Ktor 3.0: Async HTTP server/client, WebSocket, JWT authentication
- Exposed 0.55: Kotlin SQL framework with coroutines support
- Spring Boot (Kotlin): Kotlin-idiomatic Spring with WebFlux
- Compose Multiplatform: Desktop, iOS, Web, Android UI
- Testing: JUnit 5, MockK, Kotest, Turbine for Flow testing
Implementation Guide (5 minutes)
Kotlin 2.0 Features
Coroutines and Flow:
// Structured concurrency with async/await
suspend fun fetchUserWithOrders(userId: Long): UserWithOrders = coroutineScope {
val userDeferred = async { userRepository.findById(userId) }
val ordersDeferred = async { orderRepository.findByUserId(userId) }
UserWithOrders(userDeferred.await(), ordersDeferred.await())
}
// Flow for reactive streams
fun observeUsers(): Flow<User> = flow {
while (true) {
emit(userRepository.findLatest())
delay(1000)
}
}.flowOn(Dispatchers.IO)
Sealed Classes and Value Classes:
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Throwable) : Result<Nothing>
data object Loading : Result<Nothing>
}
@JvmInline
value class UserId(val value: Long) {
init { require(value > 0) { "UserId must be positive" } }
}
@JvmInline
value class Email(val value: String) {
init { require(value.contains("@")) { "Invalid email format" } }
}
Ktor 3.0 Server
Application Setup:
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
configureKoin()
configureSecurity()
configureRouting()
configureContentNegotiation()
}.start(wait = true)
}
fun Application.configureKoin() {
install(Koin) { modules(appModule) }
}
val appModule = module {
single<Database> { DatabaseFactory.create() }
single<UserRepository> { UserRepositoryImpl(get()) }
single<UserService> { UserServiceImpl(get()) }
}
fun Application.configureSecurity() {
install(Authentication) {
jwt("auth-jwt") {
realm = "User API"
verifier(JwtConfig.verifier)
validate { credential ->
if (credential.payload.audience.contains("api"))
JWTPrincipal(credential.payload) else null
}
}
}
}
fun Application.configureContentNegotiation() {
install(ContentNegotiation) {
json(Json { prettyPrint = true; ignoreUnknownKeys = true })
}
}
Routing with Authentication:
fun Application.configureRouting() {
val userService by inject<UserService>()
routing {
route("/api/v1") {
post("/auth/register") {
val request = call.receive<CreateUserRequest>()
val user = userService.create(request)
call.respond(HttpStatusCode.Created, user.toDto())
}
authenticate("auth-jwt") {
route("/users") {
get {
val page = call.parameters["page"]?.toIntOrNull() ?: 0
val size = call.parameters["size"]?.toIntOrNull() ?: 20
call.respond(userService.findAll(page, size).map { it.toDto() })
}
get("/{id}") {
val id = call.parameters["id"]?.toLongOrNull()
?: return@get call.respond(HttpStatusCode.BadRequest)
userService.findById(id)?.let { call.respond(it.toDto()) }
?: call.respond(HttpStatusCode.NotFound)
}
}
}
}
}
}
Exposed SQL Framework
Table and Entity:
object Users : LongIdTable("users") {
val name = varchar("name", 100)
val email = varchar("email", 255).uniqueIndex()
val passwordHash = varchar("password_hash", 255)
val status = enumerationByName<UserStatus>("status", 20)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp())
}
class UserEntity(id: EntityID<Long>) : LongEntity(id) {
companion object : LongEntityClass<UserEntity>(Users)
var name by Users.name
var email by Users.email
var passwordHash by Users.passwordHash
var status by Users.status
var createdAt by Users.createdAt
fun toModel() = User(id.value, name, email, passwordHash, status, createdAt)
}
Repository with Coroutines:
class UserRepositoryImpl(private val database: Database) : UserRepository {
override suspend fun findById(id: Long): User? = dbQuery {
UserEntity.findById(id)?.toModel()
}
override suspend fun save(user: User): User = dbQuery {
UserEntity.new {
name = user.name
email = user.email
passwordHash = user.passwordHash
status = user.status
}.toModel()
}
private suspend fun <T> dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO, database) { block() }
}
Spring Boot with Kotlin
WebFlux Controller:
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
@GetMapping
suspend fun listUsers(
@RequestParam(defaultValue = "0") page: Int,
@RequestParam(defaultValue = "20") size: Int
): Flow<UserDto> = userService.findAll(page, size).map { it.toDto() }
@GetMapping("/{id}")
suspend fun getUser(@PathVariable id: Long): ResponseEntity<UserDto> =
userService.findById(id)?.let { ResponseEntity.ok(it.toDto()) }
?: ResponseEntity.notFound().build()
@PostMapping
suspend fun createUser(@Valid @RequestBody request: CreateUserRequest): ResponseEntity<UserDto> {
val user = userService.create(request)
return ResponseEntity.created(URI.create("/api/users/${user.id}")).body(user.toDto())
}
}
Advanced Patterns
Compose Multiplatform
Shared UI Component:
@Composable
fun UserListScreen(viewModel: UserListViewModel, onUserClick: (Long) -> Unit) {
val uiState by viewModel.uiState.collectAsState()
when (val state = uiState) {
is UiState.Loading -> LoadingIndicator()
is UiState.Success -> UserList(state.users, onUserClick)
is UiState.Error -> ErrorMessage(state.message, onRetry = viewModel::retry)
}
}
@Composable
fun UserCard(user: User, onClick: () -> Unit) {
Card(
modifier = Modifier.fillMaxWidth().clickable(onClick = onClick),
elevation = CardDefaults.cardElevation(4.dp)
) {
Row(modifier = Modifier.padding(16.dp)) {
AsyncImage(model = user.avatarUrl, contentDescription = user.name,
modifier = Modifier.size(48.dp).clip(CircleShape))
Spacer(Modifier.width(16.dp))
Column {
Text(user.name, style = MaterialTheme.typography.titleMedium)
Text(user.email, style = MaterialTheme.typography.bodySmall)
}
}
}
}
Testing with MockK
class UserServiceTest {
private val userRepository = mockk<UserRepository>()
private val userService = UserService(userRepository)
@Test
fun `should fetch user concurrently`() = runTest {
val testUser = User(1L, "John", "john@example.com")
coEvery { userRepository.findById(1L) } coAnswers { delay(100); testUser }
val result = userService.findById(1L)
assertThat(result).isEqualTo(testUser)
}
@Test
fun `should handle Flow emissions`() = runTest {
val users = listOf(User(1L, "John", "john@example.com"))
coEvery { userRepository.findAllAsFlow() } returns users.asFlow()
userService.streamUsers().toList().also { result ->
assertThat(result).hasSize(1)
}
}
}
Gradle Build Configuration
plugins {
kotlin("jvm") version "2.0.20"
kotlin("plugin.serialization") version "2.0.20"
id("io.ktor.plugin") version "3.0.0"
}
kotlin { jvmToolchain(21) }
dependencies {
implementation("io.ktor:ktor-server-core-jvm")
implementation("io.ktor:ktor-server-netty-jvm")
implementation("io.ktor:ktor-server-content-negotiation-jvm")
implementation("io.ktor:ktor-server-auth-jwt-jvm")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
implementation("org.jetbrains.exposed:exposed-core:0.55.0")
implementation("org.jetbrains.exposed:exposed-dao:0.55.0")
implementation("org.postgresql:postgresql:42.7.3")
testImplementation("io.mockk:mockk:1.13.12")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
testImplementation("app.cash.turbine:turbine:1.1.0")
}
Context7 Integration
Library mappings for latest documentation:
/ktorio/ktor- Ktor 3.0 server/client documentation/jetbrains/exposed- Exposed SQL framework/JetBrains/kotlin- Kotlin 2.0 language reference/Kotlin/kotlinx.coroutines- Coroutines library/jetbrains/compose-multiplatform- Compose Multiplatform/arrow-kt/arrow- Arrow functional programming
Usage:
docs = await mcp__context7__get_library_docs(
context7CompatibleLibraryID="/ktorio/ktor",
topic="routing authentication jwt",
tokens=8000
)
When to Use Kotlin
Use Kotlin When:
- Developing Android applications (official language)
- Building modern server applications with Ktor
- Preferring concise, expressive syntax
- Building reactive services with coroutines and Flow
- Creating multiplatform applications (iOS, Desktop, Web)
- Full Java interoperability required
Consider Alternatives When:
- Legacy Java codebase requiring minimal changes
- Big data pipelines (prefer Scala with Spark)
Works Well With
moai-lang-java- Java interoperability and Spring Boot patternsmoai-domain-backend- REST API, GraphQL, microservices architecturemoai-domain-database- JPA, Exposed, R2DBC patternsmoai-quality-testing- JUnit 5, MockK, TestContainers integrationmoai-infra-docker- JVM container optimization
Troubleshooting
K2 Compiler: Add kotlin.experimental.tryK2=true to gradle.properties; clear .gradle for rebuild
Coroutines: Avoid runBlocking in suspend contexts; use Dispatchers.IO for blocking operations
Ktor: Ensure ContentNegotiation installed; check JWT verifier configuration; verify routing hierarchy
Exposed: Ensure all DB operations in transaction; be aware of entity loading outside transaction
Advanced Documentation
For comprehensive reference materials:
- reference.md - Complete ecosystem, Context7 mappings, testing patterns, performance
- examples.md - Production-ready code examples, Ktor, Compose, Android patterns
Last Updated: 2025-12-07 Status: Production Ready (v1.0.0)
More by modu-ai
View allPython 3.13+ development specialist covering FastAPI, Django, async patterns, data science, testing with pytest, and modern Python features. Use when developing Python APIs, web applications, data pipelines, or writing tests.
Enterprise template management with code boilerplates, feedback templates, and project optimization workflows
Flutter 3.24+ / Dart 3.5+ development specialist covering Riverpod, go_router, and cross-platform patterns. Use when building cross-platform mobile apps, desktop apps, or web applications with Flutter.
Enterprise Mermaid diagramming skill for Claude Code using MCP Playwright. Use when creating architecture diagrams, flowcharts, sequence diagrams, or visual documentation.