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 Testing in 2025: Complete Guide to Unit, Integration & UI Tests
Master KMP testing with this complete guide. Learn to write shared tests once, run everywhere. Includes Kotest, Turbine, and MockK examples with real production patterns.
Kotlin to Swift Export: Native iOS Integration Guide 2025
Kotlin 2.2.20's Swift Export delivers native Swift interop for KMP. Code examples, migration guide, and production readiness assessment for iOS teams.
How to Set Up Kotlin Multiplatform: Complete Development Guide 2025
Learn how to set up Kotlin Multiplatform for cross-platform mobile development. Complete step-by-step guide covering environment setup, Firebase integration, and production-ready configuration in 2025.

TL;DR: Why Kotlin/Wasm and Compose for Web are game-changers in 2025
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
Skip the setup, start building features
✨ For mobile + web apps:
- 🎨 Compose Multiplatform UI (all platforms)
- 🔐 Authentication (Google, Apple, Email)
- 💳 In-app purchases + subscriptions
- 📡 REST API client with Ktor
⚡ Ready to deploy:
- 🚀 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