Back to Blog

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

Kotlin/Wasm & Compose for Web in 2025: Complete Guide to Browser-First KMP Apps

TL;DR: Why Kotlin/Wasm and Compose for Web are game-changers in 2025

Kotlin/Wasm is now Beta-ready with all major browsers (Chrome, Firefox, Safari, Edge) supporting WebAssembly Garbage Collection (WasmGC).
Compose for Web hit Beta in September 2025, bringing Material 3 components, type-safe navigation, accessibility support, and cross-browser compatibility to production readiness.
Performance gains are real: Kotlin/Wasm runs almost 3x faster than JavaScript in UI-heavy scenarios, with execution speed approaching JVM performance.
The KMP web story is complete: You can now share business logic AND UI code across Android, iOS, desktop, and web, all from a single Kotlin codebase.

From mobile-first to web-everywhere: The KMP platform gap is closing

For years, Kotlin Multiplatform had a clear strength: mobile development. Companies like Netflix, McDonald's, and Cash App proved you could share code between Android and iOS with production-grade reliability.
But there was always a gap. What about the web?
Sure, you could use Kotlin/JS to compile Kotlin code to JavaScript. But let's be honest: it wasn't compelling. Bundle sizes were large, performance was mediocre, and most developers stuck with TypeScript or plain JavaScript for their web frontends.
Fast forward to 2025, and the game has changed completely.

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
The result? You can now build a single Kotlin codebase that targets Android, iOS, desktop, and the web with native performance on every platform.
This guide will show you how.

Understanding the landscape: Kotlin/JS vs Kotlin/Wasm vs Compose for Web

Before we dive into code, let's clear up the confusion. There are three different technologies here:

Kotlin/JS: The JavaScript compiler

Compiles Kotlin code directly to JavaScript. Best for sharing business logic only while using native HTML/CSS/JavaScript for UI. Works on older browsers but has larger bundle sizes.

Kotlin/Wasm: The performance champion

Compiles Kotlin code to WebAssembly for near-native speeds. Nearly 3x faster than JavaScript in UI scenarios. Best for sharing both business logic AND UI with Compose for Web. Requires modern browsers (Chrome, Firefox, Safari, Edge).

Compose for Web: Shared UI for the browser

Write UI once in Kotlin using Compose and deploy it to browsers. Powered by Kotlin/Wasm with Kotlin/JS fallback coming. Perfect for apps needing identical UI across Android, iOS, desktop, and web. Includes Material 3 components, type-safe navigation, and dark mode support.

Decision matrix: Which technology should you choose?

Use CaseBest ChoiceWhy
Sharing business logic onlyKotlin/JSLighter weight, easier JS interop
Sharing UI + logic across platformsKotlin/Wasm + Compose for WebBest performance, code reuse
Performance-critical web appKotlin/Wasm + Compose for Web3x faster than JS, near-native speed
Need to support old browsersKotlin/JS or compatibility modeWasm requires modern browsers
Complex JS library integrationKotlin/JSBetter JS interop (for now)
Data visualization / dashboardsKotlin/Wasm + Compose for WebPerformance + consistent UI

Performance: Why Kotlin/Wasm is 3x faster than JavaScript

According to JetBrains' official benchmarks:
Kotlin/Wasm is nearly 3x faster than JavaScript in UI scenarios (Compose Multiplatform rendering). This means smoother animations, faster list scrolling, and more responsive interactions.
Execution speed approaches JVM performance on Chrome for general compute tasks.
Trade-off: Kotlin/JS loads 0.25-0.5 seconds faster initially. For content websites, this matters. For apps where users stay engaged, runtime performance wins.
Why Wasm is faster: It's a compiled binary format that's already optimized, has predictable performance without JIT warmup, and provides efficient memory management with WasmGC.
When to use JavaScript instead: Simple CRUD apps, content sites prioritizing initial load speed, or heavy DOM manipulation use cases.

Getting started: Build your first Kotlin/Wasm + Compose for Web app

Enough theory. Let's write code.

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

Two options to get started:
Option A: IntelliJ IDEA wizard
  1. Open IntelliJ IDEA
  2. Select File → New → Project
  3. Choose Kotlin Multiplatform from the left panel
  4. Select Web target
  5. Enable Share UI tab (this adds Compose for Web)
  6. Set project name (e.g., "WasmDemo") and click Create
Option B: Use the official template
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

Your project will have this structure:
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

Open composeApp/src/commonMain/kotlin/App.kt:
kotlin
import 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

Check composeApp/src/wasmJsMain/kotlin/main.kt:
kotlin
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.CanvasBasedWindow @OptIn(ExperimentalComposeUiApi::class) fun main() { CanvasBasedWindow(canvasElementId = "ComposeTarget") { App() } }
This tells Compose to render your UI into a canvas element with the ID "ComposeTarget".

Step 5: Run in development mode

Two ways to run:
Option A: From IntelliJ IDEA
  1. Look for the run configuration dropdown (top-right)
  2. Select composeApp [wasmJs]
  3. Click the green play button
  4. Your browser will open at http://localhost:8080/
Option B: Terminal
bash
# Run the Wasm development server ./gradlew wasmJsBrowserDevelopmentRun # Opens browser at http://localhost:8080/ (or similar port)
You should see your app running with Material 3 styling! Try clicking the buttons and notice how responsive it feels.

Step 6: Build for production

When you're ready to deploy:
bash
# Build optimized production bundle ./gradlew wasmJsBrowserDistribution # Output location: # composeApp/build/dist/wasmJs/productionExecutable/
This generates:
  • index.html - Entry HTML file
  • *.wasm - Compiled WebAssembly binary
  • *.js - JavaScript bootstrap code
  • Other assets (CSS, resources)
Deploy these files to any static hosting:
  • 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) } } }
Works with browser forward/back buttons and supports deep linking. Users can bookmark 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

Most popular Kotlin libraries now support Wasm:
Networking: Ktor Client, kotlinx-serialization
Concurrency: kotlinx-coroutines (full async/await support)
DI: Koin
Storage: Multiplatform Settings (localStorage), SQLDelight (IndexedDB support coming)
UI: Material 3 Compose, Compose Navigation
Discover more at klibs.io.

Example: Building a REST API client with Ktor

kotlin
import 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) } ) } } } }
This exact code works on Android, iOS, desktop, and web with no platform-specific changes needed.

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)
The sweet spot: Cross-platform apps with complex business logic and UI, where you want to write it once in Kotlin and deploy everywhere with excellent performance.

Production deployment checklist

1. Enable production mode in your build.gradle.kts for optimized bundles
2. Set up CORS headers on your backend to allow Wasm app requests
3. Configure caching for .wasm and .js files (max-age=31536000, immutable)
4. Add a loading indicator while Wasm initializes (takes a moment on first load)
5. Test on all browsers: Chrome, Firefox, Safari (Dec 2024+), Edge, and mobile browsers all have full support
6. Compatibility mode coming soon: Automatic Kotlin/JS fallback for older browsers

Real-world production examples

See Kotlin/Wasm + Compose for Web in action:
  • 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
The 2025 verdict: Kotlin/Wasm + Compose for Web is production-ready for early adopters. Real companies are shipping real apps (Kotlin Playground, KotlinConf, Rijksmuseum). The tooling works, performance is excellent, and the ecosystem is growing.
The web platform gap has closed. KMP is no longer just mobile. It's truly multiplatform.

Getting started: Your next steps

Ready to build browser-first KMP apps? Here's your action plan:
  1. Try the examples - Visit Kotlin Playground and the KotlinConf app to see Kotlin/Wasm in action
  2. Clone the template - Start with kotlin-wasm-compose-template or use the IntelliJ wizard
  3. Build something small - Create a simple dashboard or CRUD app to learn the patterns
  4. Measure performance - Run your own benchmarks comparing Kotlin/Wasm vs your current web tech
  5. Join the community - Kotlin Slack (#webassembly channel) is active and helpful

Skip the setup, start building features

KMPShip gives you a production-ready Kotlin Multiplatform boilerplate that targets Android, iOS, desktop, and web with authentication, payments, CI/CD, and more pre-configured.

✨ 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)
While your competitors configure webpack and Gradle for weeks, you'll ship features on Day 1.
Join developers shipping cross-platform apps faster with Kotlin Multiplatform

Sources and references

Official documentation and guides:

Performance benchmarks and analysis:

Templates and examples:

Community and tutorials:


Note: Performance metrics are sourced from official JetBrains benchmarks and Kotlin documentation. Code examples are simplified for clarity but represent production-ready patterns. Browser compatibility reflects status as of December 2024.



Continue your Kotlin Multiplatform journey

Want to learn more about KMP topics?


Quick Questions About KMP Web Development

Still have questions about Kotlin Multiplatform for web? Get instant answers:

Ready to ship cross-platform apps faster?

Stop configuring build tools and start building features that make money. KMPShip gives you everything you need to ship Android, iOS, desktop, and web apps from a single Kotlin codebase.