What it is
SQLDelight generates typesafe Kotlin APIs from .sq files containing plain SQL, working across Android, JVM, iOS and JS.
Write schema and queries in .sq files. The Gradle plugin generates a typed API, and queries can be observed as Flow.
Installation
plugins { id("app.cash.sqldelight") version "2.0.2" }Getting started
The smallest useful thing you can do with it, and what each part means.
sql
-- src/commonMain/sqldelight/com/example/Book.sq
CREATE TABLE book (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
year INTEGER NOT NULL
);
CREATE INDEX book_year ON book(year);
selectSince:
SELECT * FROM book WHERE year >= ? ORDER BY year DESC;
insertBook:
INSERT INTO book(title, year) VALUES (?, ?);
countByYear:
SELECT year, COUNT(*) AS total FROM book GROUP BY year;kotlin
val driver = AndroidSqliteDriver(Database.Schema, context, "app.db")
val database = Database(driver)
// Typed, and observable as a Flow.
database.bookQueries.selectSince(1990)
.asFlow()
.mapToList(Dispatchers.IO)
.collect { books -> render(books) }
database.bookQueries.insertBook(title = "Dune", year = 1965)
database.transaction {
database.bookQueries.insertBook("A", 2000)
database.bookQueries.insertBook("B", 2001)
}Advanced usage
Where the library earns its place over a simpler alternative.
sql
-- 1.sqm — migrations are numbered files
ALTER TABLE book ADD COLUMN isbn TEXT;
-- Map a column to a Kotlin type at the schema level.
CREATE TABLE event (
id INTEGER PRIMARY KEY,
occurred_at INTEGER AS kotlinx.datetime.Instant NOT NULL,
payload TEXT AS kotlin.collections.List<String> NOT NULL
);Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Generated code is missing after adding a query
- The Gradle plugin runs on build. Sync or run the generateSqlDelightInterface task.
- Schema version mismatch at runtime
- A .sqm migration is missing for the new version. SQLDelight verifies migrations against the schema if you enable verifyMigrations.
Best practices
- Choose SQLDelight for Multiplatform and Room for Android-only projects.
- Keep migrations as numbered .sqm files and verify them with the schema task.
- Use asFlow().mapToList() for observable queries.
- Wrap multi-statement writes in transaction { } for atomicity and speed.
Background
Why it exists, and what it was reacting to.
From Square, SQLDelight inverts Room's model: you write SQL in its own files and the tooling generates Kotlin from it. Because it does not depend on Android APIs, the same data layer runs on iOS in a Multiplatform project.
