Seamless Room Database Integration for Kotlin Multiplatform Projects
![Illustration: Seamless Room Database Integration for Kotlin Multiplatform Projects](/assets/images/blog/2024/seamless-room-database-integration-for-kotlin-multiplatform-projects/article-header-a6b32b09.jpg)
Room is a database library that uses SQLite under the hood. In the past, it worked with Android only, but since adding support for all platforms, it works with Kotlin Multiplatform (KMP) to store data in local databases on any platform supported by KMP.
This blog post will explore the process of integrating the Room database library into your Kotlin Multiplatform projects with ease and efficiency.
Setting Up the Kotlin Multiplatform Project
Navigate to the official Kotlin Multiplatform Wizard and configure your platforms as per your needs.
For this demo, select the checkboxes for Android, iOS, and Desktop.
After selecting the platforms, select DOWNLOAD to download the ZIP file and extract the files.
You can open this project in either Android Studio or IntelliJ IDEA
Adding Dependencies
Room version 2.7.0-alpha01
and higher includes support for Kotlin Multiplatform. This post uses Kotlin version 2.0.0
with Android Gradle plugin 8.2.2
.
To add Room to your multiplatform project, include the dependencies below in libs.version.toml
:
[versions] room = "2.7.0-alpha03" ksp = "2.0.0-1.0.21" sqlite = "2.5.0-SNAPSHOT" [libraries] room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } sqlite-bundled = { module= "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" } [plugins] ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" }
Now, you’ll add these to your build.gradle.kts
file.
Append the plugins below in the plugins
block and the dependencies below in the commonMain.dependencies
block:
plugins { alias(libs.plugins.ksp) alias(libs.plugins.room) ... commonMain.dependencies { implementation(libs.room.runtime) implementation(libs.sqlite.bundled) ...
Add the Room database schema path, along with KSP support for the Room compiler, at the end of the build.gradle.kts
file:
room { schemaDirectory("$projectDir/schemas") } dependencies { // KSP support for Room Compiler. kspCommonMainMetadata(libs.room.compiler) } // Solves implicit dependency issue and IDEs source code detection. kotlin.sourceSets.commonMain { tasks.withType<KspTaskMetadata> { kotlin.srcDir(destinationDirectory) } }
You’ve now added all the required dependencies for Room to your KMP project.
Adding Database Classes
Next, create the Database
class with DAOs
and Entities
inside the CommonMain
package:
// shared/src/commonMain/kotlin/Database.kt @Database(entities = [FruitEntity::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun getFruitDao(): FruitDao } @Dao interface FruitDao { @Upsert // Insert and update entities. suspend fun upsert(fruit: FruitEntity) @Delete suspend fun delete(fruit: FruitEntity) @Query("SELECT * FROM FruitEntity") fun getAllAsFlow(): Flow<List<FruitEntity>> } @Entity data class FruitEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0L, val name: String, val description: String, val count: Int = 0 )
Next, add platform-specific code to create your database builder.
Android
// shared/src/androidMain/kotlin/Database.kt fun getDatabaseBuilder(context: Context) = with(context) { val dbFile = applicationContext.getDatabasePath("room_android.db") Room.databaseBuilder<AppDatabase>( context = applicationContext, name = dbFile.absolutePath ) }
iOS
// shared/src/iosMain/kotlin/Database.kt fun getDatabaseBuilder() = Room.databaseBuilder<AppDatabase>( name = NSHomeDirectory() + "/room_ios.db", factory = { AppDatabase::class.instantiateImpl() } )
Desktop
// shared/src/commonMain/kotlin/Database.kt fun getDatabaseBuilder() = Room.databaseBuilder<AppDatabase>( name = File(System.getProperty("java.io.tmpdir"), "room_desktop.db").absolutePath )
Here’s the database builder you use to initialize your AppDatabase
:
// shared/src/commonMain/kotlin/Database.kt fun getRoomDatabase(builder: RoomDatabase.Builder<AppDatabase>): AppDatabase { return builder .addMigrations(MIGRATIONS) .fallbackToDestructiveMigrationOnDowngrade() .setDriver(BundledSQLiteDriver()) .setQueryCoroutineContext(Dispatchers.IO) .build() }
At last, the Room database setup is complete! Now, with the getRoomDatabase
method, you can easily retrieve the database instance.
Conclusion
This post demonstrated how only a few lines of code can grant the power of databases in multiple platforms in a single codebase. With the instance of AppDatabase
, it’s possible to perform all database transactions — like searching, inserting, and deleting data — regardless of which platform you’re on. Magic!
For a working example project of Room database implementation in KMP, refer to the following GitHub repository.