Skip to content

SeijinD/KMPWebRoom

Repository files navigation

KMP Web Room

A minimal Kotlin Multiplatform project demonstrating Room 3 database running in the browser via Kotlin/Wasm and SQLite OPFS.

Data is stored persistently in the browser using the Origin Private File System (OPFS) — a real SQLite database that survives page refreshes.

Architecture

┌─────────────────────────────────────────────────────┐
│                    commonMain                       │
│  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │
│  │NoteEntity│  │ NoteDao  │  │   AppDatabase     │  │
│  │ @Entity  │  │  @Dao    │  │ @ConstructedBy    │  │
│  └──────────┘  └──────────┘  └───────────────────┘  │
│                                    │                │
│                       expect getDatabaseBuilder()   │
└────────────────────────────────────┬────────────────┘
                                     │
┌────────────────────────────────────▼────────────────┐
│                   wasmJsMain                        │
│                                                     │
│  actual fun getDatabaseBuilder()                    │
│    Room.databaseBuilder(name = "notes.db")          │
│      .setDriver(WebWorkerSQLiteDriver(...))         │
│                         │                           │
│            @JsFun → new Worker('worker.js')         │
│                    Web Worker thread                │
│                  ┌──────────────────┐               │
│                  │ SQLite WASM      │               │
│                  │ OPFS storage     │               │
│                  └──────────────────┘               │
└─────────────────────────────────────────────────────┘

Tech Stack

Library Version
Kotlin 2.3.20
Compose Multiplatform 1.10.3
Room 3.0.0-alpha03
AndroidX SQLite Web 2.7.0-alpha03
KSP 2.3.6
Koin 4.2.0

Run

./gradlew composeApp:wasmJsBrowserDevelopmentRun

Opens at http://localhost:8080.

Note: The dev server is configured with Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers, required for SharedArrayBuffer / OPFS.

Project Structure

composeApp/
├── sqlite-wasm-worker/              # Local npm package — SQLite Web Worker
│   ├── package.json
│   └── worker.js
├── webpack.config.d/
│   └── cors-headers.js              # COOP/COEP headers for OPFS
├── src/
│   ├── commonMain/kotlin/.../
│   │   ├── data/
│   │   │   ├── NoteEntity.kt       # @Entity
│   │   │   ├── NoteDao.kt          # @Dao with Flow
│   │   │   ├── AppDatabase.kt      # @Database + @ConstructedBy
│   │   │   └── DatabaseBuilder.kt   # expect fun
│   │   ├── di/
│   │   │   └── AppModule.kt        # Koin module
│   │   └── ui/
│   │       ├── App.kt              # Compose UI
│   │       └── NotesViewModel.kt   # ViewModel with StateFlow
│   └── wasmJsMain/kotlin/.../
│       ├── data/
│       │   └── DatabaseBuilder.wasmJs.kt  # actual — WebWorkerSQLiteDriver
│       └── main.kt                        # Entry point + Koin init
└── build.gradle.kts

How It Works

The Room database layer (Entity, DAO, Database) lives in commonMain — identical to Android. The only web-specific part is the actual fun getDatabaseBuilder() which uses WebWorkerSQLiteDriver to bridge Room with a SQLite instance running inside a Web Worker via OPFS.

The worker.js is the official AndroidX reference implementation and handles four commands over postMessage: open, prepare, step, close.

References

License

Copyright 2026 Georgios Karanikolas

Licensed under the Apache License, Version 2.0

See LICENSE for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors