If you’re learning Android development and wondering how to insert data into Room database in Android, this step-by-step guide is for you. We’ll build a tiny offline feature that saves items locally using Room, Kotlin coroutines, and a simple Jetpack Compose UI. You’ll see how to create your Entity, DAO, and Database classes, how to use the Room DAO insert method correctly, how to handle conflicts, and how to verify that your data was saved. We’ll also include a compact Java example for beginners who are not yet using Kotlin.
What is Room database in Android and why use it?
Room is the official SQLite object-mapping library from Android Jetpack. It lets you define data models as Kotlin/Java classes (Entities), write type-safe queries in DAOs, and get compile-time validation for SQL. Compared to using raw SQLiteOpenHelper, Room reduces boilerplate, catches query errors early, and integrates cleanly with coroutines and Kotlin Flows for reactive updates.
- Compile-time checked SQL and schema migrations
- Easy data access with DAOs (@Insert, @Update, @Delete, @Query)
- Seamless integration with Kotlin coroutines and Flow
- Battle-tested performance and reliability for saving data locally in Android
What you’ll build
We’ll build a minimal “Products” example to demonstrate a Room database insert example in Android. You’ll:
- Create a Product entity with an auto-generated primary key
- Define a DAO with @Insert and @Upsert methods
- Build an AppDatabase to provide the DAO
- Use a Repository and ViewModel to call inserts off the main thread
- Create a simple Jetpack Compose screen to input and view products
- Learn how to insert a list of items and how to verify success
Project setup (Kotlin + Room + coroutines)
Room 2.8.x is stable and widely used. Room 3.0 (androidx.room3) is also available and primarily targets Kotlin Multiplatform while preserving the core @Insert/@Upsert patterns for Android apps. New Android projects should prefer KSP over KAPT for faster builds.
Gradle configuration (Room 2.8.x with KSP)
Optional (Room 3.0 on Android)
If you adopt Room 3.0, artifacts come from the androidx.room3 group. Your @Insert/@Upsert usage stays the same. Check the latest release notes before upgrading.
Step 1: Create the Entity
Our Product will have an auto-generated ID, a name, a quantity, and a timestamp.
Step 2: Create the DAO with @Insert and @Upsert
DAOs define how you access the database. Insert methods should be suspend so they run off the main thread with coroutines. Room will generate the SQL for you.
Notes for beginners:
- @Insert can accept a single entity, a vararg, or a List. It can return a
LongorList<Long>for row IDs. This is handy for navigation or showing confirmation. - onConflict defines what happens if a row with the same primary key already exists. Common choices are
ABORT(default),IGNORE, andREPLACE. - @Upsert lets you write “insert or update” logic without managing both paths yourself.
| Option | Best for | Conflict behavior | Return values |
|---|---|---|---|
@Insert(ABORT) (default) |
Strict inserts when duplicates should fail | Throws on primary key conflict | Single Long or List<Long> of rowIds |
@Insert(IGNORE) |
Bulk inserts where duplicates can be skipped | Skips conflicting rows | IDs for inserted rows; -1 for skipped ones |
@Insert(REPLACE) |
When you want “overwrite” semantics | Deletes conflicting row then inserts new | RowIds like @Insert (note REPLACE side effects) |
@Upsert |
Insert-or-update without branching logic | Inserts new rows; updates existing by primary key | Often used without return; use @Insert if you need rowIds |
Step 3: Build the RoomDatabase
The database class ties entities and DAOs together. Create a singleton instance and avoid allowing main-thread queries in production.
Avoid allowMainThreadQueries() in real apps; Room is designed to run I/O off the main thread using coroutines.
Step 4: Repository and ViewModel
The Repository encapsulates data operations and the ViewModel coordinates UI events and background work using viewModelScope.
Step 5: Simple Jetpack Compose UI
This UI lets a user type a product name and quantity, tap Save, and immediately see the inserted item below using a Flow list.
How to insert a list of items into Room database Android
Room can insert a List in one call. You’ll get a list of rowIds in return when using @Insert. If you prefer “insert or update” semantics, use @Upsert.
How can I check if data was inserted into Room successfully?
- For @Insert, check the returned
LongrowId. A positive value indicates success. - For @Insert IGNORE with a list, conflicting rows return
-1in the result list, so you can detect which inserts were skipped. - Observe your data via
Flow<List<Product>>(or LiveData) to confirm entries appear after calling insert.
Java version: Android Room insert Java tutorial (minimal)
If you’re learning with Java, here is a beginner-friendly version using a background thread. This is a Room database step by step guide snippet for insert.
This Room database insert example Android (Java) avoids main-thread database work and shows how to observe results using LiveData<List<Note>>.
Transactions and error handling
- Use
withTransaction { ... }on the database for multi-step operations that must succeed or fail as a unit. - Wrap UI calls with try/catch in your ViewModel to display meaningful errors.
- Prefer
@Upsertwhen synchronization logic would otherwise require you to manually check and update existing rows.
Performance tips and best practices
- Do not enable
allowMainThreadQueries()in production; keep inserts off the main thread. - Use KSP for Room’s compiler to speed up builds in Kotlin projects.
- Use List or vararg inserts to batch data and reduce overhead.
- Return row IDs from inserts when you need to navigate to details immediately after saving.
- Migrate to @Upsert for clean insert-or-update logic (Room 2.5+).
- Dependencies added:
room-runtime,room-ktx, and KSP compiler - Entity annotated with
@Entityand primary key set (autoGenerate if needed) - DAO has
@Insert(and optionally@Upsert) methods markedsuspend - Database built as a singleton with
Room.databaseBuilder(noallowMainThreadQueries()) - Repository encapsulates DAO calls; ViewModel uses
viewModelScope.launch - UI triggers insert and observes
Flow<List<T>>orLiveDatafor updates - Bulk inserts: choose proper
onConflict(e.g., IGNORE for skipping duplicates) - Verification: check returned rowId(s) and ensure list updates in UI
Output / Result
After running the app:
- Typing a name (e.g., “Notebook”) and quantity (e.g., 2) and pressing Save shows a toast like “Saved with id = 1”.
- The new item appears instantly under “Saved products:” because the UI observes a
Flow<List<Product>>from the DAO. - Inserting a list returns a list of row IDs, so you can confirm which inserts succeeded (non-negative IDs) or were ignored (-1 on IGNORE conflicts).
FAQ
What is Room database in Android and why use it?
Room is a high-level wrapper over SQLite that provides type-safe DAOs, compile-time SQL validation, and integrations with Kotlin coroutines and Flows. It helps you save data locally in Android with fewer bugs and less boilerplate.
How do I create an Entity, DAO, and Database for Room?
Create an @Entity data class for each table, define a @Dao interface with @Insert, @Query, etc., and implement a RoomDatabase subclass annotated with @Database that lists your entities and DAOs. Build a singleton instance using Room.databaseBuilder(...).
How do I insert data into Room using Kotlin?
Define a suspend @Insert method in your DAO and call it from a ViewModel using viewModelScope.launch { ... }. For example, @Insert suspend fun insert(product: Product): Long, then call it via a Repository. See the Kotlin code above for a complete flow using Compose.
How do I insert data into Room using Java?
Use a DAO method like @Insert long insert(Note note) and run it on a background thread (e.g., Executors.newSingleThreadExecutor()) to avoid blocking the main UI thread. Use LiveData queries to observe results in the UI.
How can I check if data was inserted into Room successfully?
Check the returned rowId from @Insert. If you use onConflict = OnConflictStrategy.IGNORE for bulk inserts, failed inserts return -1. You can also verify success by observing the table via a Flow or LiveData and confirming the new rows appear.
Troubleshooting and common mistakes
- Doing DB work on the main thread: Use
suspendDAO methods and call them from a coroutine in your ViewModel. - Forgetting an auto-generated primary key: Make sure your entity uses
@PrimaryKey(autoGenerate = true)if you want Room to assign IDs. - Using KAPT in new Kotlin projects: Prefer KSP for Room’s compiler to reduce build times.
- Writing custom SQL for upsert: Use
@Upserton Room 2.5+ instead of managing insert/update branches yourself. - Not handling duplicates: Pick the right
onConflictstrategy (ABORT,IGNORE, orREPLACE) or switch to@Upsert.
Recap: Android Room insert Kotlin tutorial (beginner-friendly)
You learned how to add data to Room database with DAO in Android using @Insert and @Upsert, how to return row IDs, how to insert a list of items, and how to wire everything through a Repository and ViewModel so work runs off the main thread. The same concepts apply when you use Java, with background threads instead of coroutines.
Sources / Further reading
- Accessing data using Room DAOs: https://developer.android.com/training/data-storage/room/accessing-data
- @Insert — API reference: https://developer.android.com/reference/androidx/room/Insert
- @Upsert — API reference: https://developer.android.com/reference/androidx/room/Upsert
- Room release notes (2.8.x): https://developer.android.com/jetpack/androidx/releases/room
- Room 3.0 release notes: https://developer.android.com/jetpack/androidx/releases/room3
- Modernizing Room (Android Developers Blog): https://developer.android.com/blog/posts/modernizing-the-room
- Kotlin Flows on Android: https://developer.android.com/kotlin/flow
- RoomDatabase.Builder.allowMainThreadQueries — why to avoid it: API reference
With these patterns, you now have a solid, future-proof way to insert data into Room database in Android—ready for your next app or course project.


