Kotlin/Wasm & Compose for Web in 2025: Complete Guide to Browser-First KMP Apps
Build high-performance web apps with Kotlin/Wasm and Compose for Web. Learn when to use Wasm vs JavaScript, see real benchmarks showing 3x faster performance, and build your first browser app with step-by-step examples.
Posted by
Related reading
Kotlin Multiplatform image loading with Coil 3 in 2026
Learn how to load and cache images in Kotlin Multiplatform using Coil 3 with this comprehensive guide for Compose Multiplatform.
Kotlin Multiplatform in-app purchases with RevenueCat
Learn how to implement in-app purchases and subscriptions in your Kotlin Multiplatform app using RevenueCat with our step-by-step guide.
Kotlin Multiplatform push notifications: a complete guide 2026
Learn how to implement Kotlin Multiplatform push notifications for Android and iOS using Firebase Cloud Messaging and APNs.

From mobile-first to web-everywhere: The KMP platform gap is closing
The 2025 breakthrough: Why everything changed this year
- Safari adopted WasmGC in December 2024: The last major browser holdout finally supports WebAssembly Garbage Collection, meaning Kotlin/Wasm apps now run on 100% of modern browsers
- Compose for Web hit Beta in September 2025: No longer experimental, it's production-ready for early adopters
- Performance benchmarks prove it: Kotlin/Wasm is nearly 3x faster than JavaScript in UI-heavy workloads
- Real production apps exist: Kotlin Playground, KotlinConf app, and Rijksmuseum Demo all run on Kotlin/Wasm in production
Understanding the landscape: Kotlin/JS vs Kotlin/Wasm vs Compose for Web
Kotlin/JS: The JavaScript compiler
Kotlin/Wasm: The performance champion
Compose for Web: Shared UI for the browser
Decision matrix: Which technology should you choose?
| Use Case | Best Choice | Why |
|---|---|---|
| Sharing business logic only | Kotlin/JS | Lighter weight, easier JS interop |
| Sharing UI + logic across platforms | Kotlin/Wasm + Compose for Web | Best performance, code reuse |
| Performance-critical web app | Kotlin/Wasm + Compose for Web | 3x faster than JS, near-native speed |
| Need to support old browsers | Kotlin/JS or compatibility mode | Wasm requires modern browsers |
| Complex JS library integration | Kotlin/JS | Better JS interop (for now) |
| Data visualization / dashboards | Kotlin/Wasm + Compose for Web | Performance + consistent UI |
Performance: Why Kotlin/Wasm is 3x faster than JavaScript
Getting started: Build your first Kotlin/Wasm + Compose for Web app
Prerequisites
- IntelliJ IDEA (2025.3+ recommended) or Android Studio with Kotlin Multiplatform plugin
- JDK 11+ (JDK 17 recommended for Compose projects)
- Modern browser - Chrome, Firefox, Safari, or Edge
Step 1: Create your project
- Open IntelliJ IDEA
- Select File → New → Project
- Choose Kotlin Multiplatform from the left panel
- Select Web target
- Enable Share UI tab (this adds Compose for Web)
- Set project name (e.g., "WasmDemo") and click Create
bash# Clone the official Compose Wasm template git clone https://github.com/Kotlin/kotlin-wasm-compose-template.git cd kotlin-wasm-compose-template
Step 2: Project structure overview
WasmDemo/
├── composeApp/
│ ├── src/
│ │ ├── commonMain/ # Shared code (Android, iOS, Web, Desktop)
│ │ │ └── kotlin/
│ │ │ └── App.kt # Your main Compose UI
│ │ ├── wasmJsMain/ # Web-specific code (Kotlin/Wasm)
│ │ │ └── kotlin/
│ │ │ └── main.kt # Web entry point
│ │ └── androidMain/ # (if targeting Android)
│ └── build.gradle.kts
├── gradle/
└── settings.gradle.kts
Step 3: Your first Compose for Web UI
composeApp/src/commonMain/kotlin/App.kt:kotlinimport androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun App() { var count by remember { mutableStateOf(0) } MaterialTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Column( modifier = Modifier .fillMaxSize() .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = "Welcome to Kotlin/Wasm + Compose for Web!", style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(24.dp)) Text( text = "You've clicked $count times", style = MaterialTheme.typography.bodyLarge ) Spacer(modifier = Modifier.height(16.dp)) Button(onClick = { count++ }) { Text("Click me!") } Spacer(modifier = Modifier.height(16.dp)) Button( onClick = { count = 0 }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.secondary ) ) { Text("Reset") } } } } }
Step 4: Web entry point
composeApp/src/wasmJsMain/kotlin/main.kt:kotlinimport androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.CanvasBasedWindow @OptIn(ExperimentalComposeUiApi::class) fun main() { CanvasBasedWindow(canvasElementId = "ComposeTarget") { App() } }
Step 5: Run in development mode
- Look for the run configuration dropdown (top-right)
- Select composeApp [wasmJs]
- Click the green play button
- Your browser will open at
http://localhost:8080/
bash# Run the Wasm development server ./gradlew wasmJsBrowserDevelopmentRun # Opens browser at http://localhost:8080/ (or similar port)
Step 6: Build for production
bash# Build optimized production bundle ./gradlew wasmJsBrowserDistribution # Output location: # composeApp/build/dist/wasmJs/productionExecutable/
index.html- Entry HTML file*.wasm- Compiled WebAssembly binary*.js- JavaScript bootstrap code- Other assets (CSS, resources)
- GitHub Pages - Free, easy setup
- Cloudflare Workers - Edge deployment
- Netlify / Vercel - One-command deployment
- AWS S3 + CloudFront - Enterprise-grade
Real-world patterns: Building production Compose for Web apps
Type-safe navigation with deep linking
kotlin@Composable fun App() { val navController = rememberNavController() NavHost(navController, startDestination = "home") { composable("home") { HomeScreen(navController) } composable("profile/{userId}") { backStackEntry -> val userId = backStackEntry.arguments?.getString("userId") ProfileScreen(userId = userId) } } }
yourapp.com/profile/123.HTML interoperability
kotlin@Composable fun HybridComponent() { Column { Text("This is Compose", style = MaterialTheme.typography.headlineMedium) Div(attrs = { style { property("padding", "16px") } }) { Text("This is native HTML/CSS") } Button(onClick = { }) { Text("Compose Button") } } }
Library ecosystem: What works with Kotlin/Wasm today
Example: Building a REST API client with Ktor
kotlinimport io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.Serializable import kotlinx.coroutines.flow.MutableStateFlow @Serializable data class User(val id: Int, val name: String, val email: String) class UserRepository { private val client = HttpClient { install(ContentNegotiation) { json() } } suspend fun fetchUsers(): List<User> { return client.get("https://api.example.com/users").body() } suspend fun createUser(name: String, email: String): User { return client.post("https://api.example.com/users") { setBody(mapOf("name" to name, "email" to email)) }.body() } } // Use in your Compose UI @Composable fun UserListScreen() { var users by remember { mutableStateOf<List<User>>(emptyList()) } var loading by remember { mutableStateOf(true) } val repository = remember { UserRepository() } LaunchedEffect(Unit) { users = repository.fetchUsers() loading = false } if (loading) { CircularProgressIndicator() } else { LazyColumn { items(users) { user -> ListItem( headlineContent = { Text(user.name) }, supportingContent = { Text(user.email) } ) } } } }
Compose for Web vs traditional web frameworks
Use Compose for Web when:
- You're already using Kotlin Multiplatform for mobile (easy to add web target)
- You want one UI codebase for Android, iOS, desktop, and web
- You're building internal tools, dashboards, or data-heavy apps
- Performance is critical (data viz, real-time updates)
- Your team knows Kotlin, not JavaScript
Use React/Vue/Svelte when:
- Building marketing websites or blogs (need SEO and SSR)
- Need the fastest time-to-market (larger ecosystem)
- Your team is 100% web-focused (not targeting mobile/desktop)
- Must support very old browsers (IE11, ancient Safari)
Production deployment checklist
Real-world production examples
- Kotlin Playground: Full IDE in the browser with real-time compilation at near-native speeds
- KotlinConf App: Conference app with shared UI across Android, iOS, and web
- Rijksmuseum Demo: Data-heavy museum collection browser handling thousands of items smoothly
- Jetsnack Wasm Demo: E-commerce app with complex Material 3 UI patterns
What's coming in 2025-2026
- Stable Compose for Web (late 2025 / early 2026)
- Compatibility mode: Automatic Wasm/JS fallback for all browsers
- Stable @JsExport: Better JavaScript interoperability
- Modern JavaScript output (ES2015+): Smaller bundles, faster execution
- Multithreading support: Web Workers for parallel execution
- Enhanced debugging: Better source maps and IDE integration
- TypeScript wrapper generation: Auto-generated definitions for seamless JS integration
Should you adopt Kotlin/Wasm + Compose for Web in 2025?
Adopt now if:
- You're building a new cross-platform app or already have a KMP mobile app
- You're comfortable with Beta software (stable enough for production)
- Performance matters (data viz, real-time updates)
- Your team knows Kotlin
Wait if:
- Company policy forbids Beta software (Stable coming late 2025 / early 2026)
- Building a pure web app with no mobile/desktop plans
- SEO is critical (need server-side rendering)
- Must support IE11 or ancient browsers
Getting started: Your next steps
- Try the examples - Visit Kotlin Playground and the KotlinConf app to see Kotlin/Wasm in action
- Clone the template - Start with kotlin-wasm-compose-template or use the IntelliJ wizard
- Build something small - Create a simple dashboard or CRUD app to learn the patterns
- Measure performance - Run your own benchmarks comparing Kotlin/Wasm vs your current web tech
- Join the community - Kotlin Slack (#webassembly channel) is active and helpful
- 🎨 Compose Multiplatform UI (all platforms)
- 🔐 Authentication (Google, Apple, Email)
- 💳 In-app purchases + subscriptions
- 📡 REST API client with Ktor
- 🚀 CI/CD for Android, iOS, and web
- 📱 Complete sample app (not just hello world)
- 📚 Comprehensive documentation
- 🏗️ Clean architecture (testable, scalable)
Sources and references
Official documentation and guides:
- Get started with Kotlin/Wasm and Compose Multiplatform - Official Kotlin Documentation
- Kotlin/Wasm Overview - Kotlin Documentation
- Compose Multiplatform 1.9.0 Released: Compose for Web Goes Beta - JetBrains Blog
- Present and Future of Kotlin for Web - JetBrains Blog
- What's Next for Kotlin Multiplatform and Compose Multiplatform – August 2025 Update - JetBrains Blog
Performance benchmarks and analysis:
- Kotlin/Wasm Benchmarks Collection - Official Kotlin GitHub
- Kotlin VS Javascript benchmarks - Programming Language Benchmarks
- Compose for Web (WASM) – What and Why? - Handstand Sam
Templates and examples:
- kotlin-wasm-compose-template - Official Kotlin Template Repository
- kotlin-wasm-examples - Official Examples Repository
- Kotlin Playground - Production Kotlin/Wasm App
Community and tutorials:
- Getting Started with Web Assembly and Kotlin Multiplatform - Touchlab
- klibs.io - Kotlin Multiplatform Library Directory
- Kotlin Slack Community - #webassembly channel
Continue your Kotlin Multiplatform journey
- Compose Multiplatform for iOS Stable in 2025: What Developers Need to Know
- Kotlin Multiplatform vs Flutter vs React Native: The 2025 Developer Guide
- How to Set Up Kotlin Multiplatform: Complete Development Guide 2025
- Big Tech's Secret Weapon: How Netflix, McDonald's & Cash App Ship Faster with KMP
Quick Questions About KMP Web Development
- Do I need a Mac for iOS development? - Platform requirements explained
- How long does setup actually take? - Real timeline expectations
- What's the total cost comparison? - KMP vs traditional development costs
Build your KMP app faster
Skip the setup and start shipping with a production-ready Kotlin Multiplatform starter kit.