0Pricing
Kotlin Academy · Lesson

Defining Tables with the Table DSL

Define typed table schemas with columns, primary keys, and foreign keys.

Defining Tables with the Table DSL is a free Kotlin Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Exposed Table Objects

In Exposed, database tables are represented as Kotlin singleton objects that extend Table (Query DSL) or IntIdTable/LongIdTable/UUIDTable (DAO layer). Column definitions are Kotlin properties.

A Basic Table Definition

Extend Table and define columns using the built-in column factory functions:

import org.jetbrains.exposed.sql.Table

object Users : Table("users") {
    val id    = long("id").autoIncrement()
    val name  = varchar("name", 100)
    val email = varchar("email", 255).uniqueIndex()
    val age   = integer("age").nullable()

    override val primaryKey = PrimaryKey(id)
}

Column Types

Exposed provides factory functions for common SQL types:

  • integer("col"), long("col"), short("col")
  • varchar("col", length), text("col")
  • bool("col"), double("col"), decimal("col", precision, scale)
  • datetime("col"), date("col"), timestamp("col")
  • blob("col"), uuid("col"), binary("col", length)

Nullable Columns

Call .nullable() on any column to allow NULL values. The Kotlin type becomes nullable (String? instead of String):

object Products : Table("products") {
    val id          = long("id").autoIncrement()
    val name        = varchar("name", 200)
    val description = text("description").nullable()
    override val primaryKey = PrimaryKey(id)
}

Default Values

Use .default(value) for a Kotlin-side default (applied before insert) or .defaultExpression(expr) for a database-side SQL default:

object Orders : Table("orders") {
    val id        = long("id").autoIncrement()
    val status    = varchar("status", 20).default("PENDING")
    val createdAt = datetime("created_at")
        .defaultExpression(CurrentDateTime)
    override val primaryKey = PrimaryKey(id)
}

Indexes and Unique Constraints

Call .index() for a regular index or .uniqueIndex() for a unique index directly on a column. For composite indexes, use the index() function on the Table:

object Articles : Table("articles") {
    val id    = long("id").autoIncrement()
    val title = varchar("title", 300).index()
    val slug  = varchar("slug", 300).uniqueIndex()
    override val primaryKey = PrimaryKey(id)
}

Foreign Keys

Use .references() to declare a foreign key constraint between columns. Pass the referenced column and optionally the onDelete and onUpdate actions:

object Posts : Table("posts") {
    val id       = long("id").autoIncrement()
    val authorId = long("author_id").references(Users.id, onDelete = ReferenceOption.CASCADE)
    val title    = varchar("title", 300)
    override val primaryKey = PrimaryKey(id)
}

IdTable Variants

For the DAO layer, use typed ID tables instead of plain Table:

  • IntIdTable("name")Int auto-increment primary key named id
  • LongIdTable("name")Long auto-increment primary key
  • UUIDTable("name") — UUID primary key
object Users : LongIdTable("users") {
    val name  = varchar("name", 100)
    val email = varchar("email", 255).uniqueIndex()
}

Composite Primary Keys

Define a composite primary key by passing multiple columns to PrimaryKey():

object UserRoles : Table("user_roles") {
    val userId = long("user_id").references(Users.id)
    val roleId = long("role_id").references(Roles.id)
    override val primaryKey = PrimaryKey(userId, roleId)
}

Enum Columns

Store Kotlin enum values as strings or ordinals using enumerationByName() or enumeration():

enum class Status { ACTIVE, INACTIVE, BANNED }

object Users : LongIdTable("users") {
    val name   = varchar("name", 100)
    val status = enumerationByName<Status>("status", 20)
}

Applying Schema Changes

Call SchemaUtils.createMissingTablesAndColumns() to add missing tables and columns without dropping existing data — a safe migration for development. For production, use a migration tool like Flyway or Liquibase.

transaction {
    SchemaUtils.createMissingTablesAndColumns(Users, Posts, Orders)
}

Quick Check

How do you declare a foreign key from Posts.authorId to Users.id in Exposed's Table DSL?

Recap: Defining Tables with the Table DSL

Key takeaways:

  • Tables are objects extending Table, LongIdTable, etc.
  • Columns: varchar, integer, long, bool, datetime, uuid, etc.
  • .nullable(), .default(), .uniqueIndex(), .references() modify columns
  • Composite primary keys: PrimaryKey(col1, col2)
  • Apply schema with SchemaUtils.create() or createMissingTablesAndColumns()

Frequently asked questions

Is the “Defining Tables with the Table DSL” lesson free?

Yes — the full text of “Defining Tables with the Table DSL” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “Defining Tables with the Table DSL”?

Define typed table schemas with columns, primary keys, and foreign keys. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Defining Tables with the Table DSL” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Exposed Setup: Database Connection and Transaction DSL
  2. Defining Tables with the Table DSL
  3. CRUD with the Query DSL: insert, select, update, delete
  4. Exposed DAO: Entity Classes and Relationships
← Back to Kotlin Academy