Models
August 23, 2026 · View on GitHub
A table is a Kotlin class with @Table and at least one @PrimaryKey.
@Table
data class User(
@PrimaryKey(autoincrement = true) val id: Int = 0,
val name: String,
val email: String?,
)
Register it on @Database(tables = [User::class]).
Generated:
User.Companion— column properties (User.name),select from User, and theModelAdapter<User>used at runtime (User.Companion as ModelAdapter<User>)User_Adapter.kt— internal helpers (TableOps, binders, property getters) wired into the companionuserAdapter— abstractvalon your database class; the generatedcreate()passes the companion
You do not reference *_Table types or adapter delegate objects in app code.
Columns
@Table(allFields = true) (default) maps every property. Use @ColumnIgnore to skip one. Set allFields = false and annotate each stored property with @Column, @PrimaryKey, or @ForeignKey.
@Table
data class User(
@PrimaryKey val id: String,
val name: String,
@ColumnIgnore val transientFlag: Boolean = false,
)
Rename a column with @Column(name = "first_name").
Nullability is respected. Non-null properties are not assigned null from a cursor.
Supported types
- Primitives and their nullable counterparts
String,Booleancom.dbflow5.data.Blob- Types with a TypeConverter
- Other tables only as
@ForeignKey(or@PrimaryKey+@ForeignKey)
Not supported as columns: List, Map, or other generic containers. Use a related table.
Primary keys
One or more @PrimaryKey. Autoincrement: @PrimaryKey(autoincrement = true) — only one, and do not mix with other primary keys.
@Table
data class Membership(
@PrimaryKey val userId: String,
@PrimaryKey val groupId: String,
)
Unique
@Table
data class User(
@PrimaryKey val id: Int = 0,
@Unique val email: String,
)
Composite unique:
@Table(
uniqueColumnGroups = [
UniqueGroup(groupNumber = 1, uniqueConflict = ConflictAction.FAIL),
]
)
data class Enrollment(
@PrimaryKey val id: Int = 0,
@Unique(unique = false, uniqueGroups = [1]) val studentId: Int,
@Unique(unique = false, uniqueGroups = [1]) val courseId: Int,
)
Defaults
@Column(defaultValue = "…") is the SQL default used when the property is null on save — not a Kotlin constructor default.
FTS
@Fts3 / @Fts4 mark virtual tables. See the SQLite FTS docs.
Temporary / deferred create
@Table(temporary = true, createWithDatabase = false)
data class Scratch(@PrimaryKey val id: Int)
createWithDatabase = false keeps the generated adapter but does not CREATE TABLE at open (legacy tables for migrations).
Constructor
A no-arg constructor is required for codegen. data class properties need defaults when they are not nullable, or supply a secondary constructor. val properties are fine.
Model companions
The compiler plugin adds a companion object to each @Table, @ModelView, and @Query class:
@Table
data class User(@PrimaryKey val id: Int, val name: String)
// Generated conceptually:
// companion object : ModelAdapterImpl<User>(), AdapterCompanion<User> {
// val name: PropertyStart<String, User> // column property
// }
Use User.name in where, set, and insert clauses. Use userAdapter (or
User.Companion as ModelAdapter<User>) for save, select, and other adapter
operations. Both refer to the same runtime object.
@Query and @ModelView companions extend QueryAdapterImpl and
ViewAdapterImpl respectively.
DBRepresentable.name vs column name
DBRepresentable.name is the quoted SQL table or view name (for example `User`).
When a column is also called name, read the table name with sqlName() if you
are working with a raw DBRepresentable reference. Query DSL code uses
sqlName() internally, so userAdapter.createIndexOn(…, User.name) and similar
calls behave as expected.