Programming language: Kotlin
Tags: Database    
Latest version: v0.2.0

krush alternatives and similar libraries

Based on the "Database" category

Do you think we are missing an alternative of krush or a related project?

Add another 'Database' Library



Sonatype Nexus (Repository) CircleCI Sputnik

Krush is a lightweight persistence layer for Kotlin based on Exposed SQL DSL. It’s similar to Requery and Micronaut-data jdbc, but designed to work idiomatically with Kotlin and immutable data classes.

It’s based on a compile-time JPA annotation processor that generates Exposed DSL table and objects mappings for you. This lets you instantly start writing type-safe SQL queries without need to write boilerplate infrastructure code.


  • (type-safe) SQL-first - use type-safe SQL-like DSL in your queries, no string or method name parsing
  • Minimal changes to your domain model - no need to extend external interfaces and used special types - just add annotations to your existing domain model
  • Explicit fetching - you specify explicitly in query what data you want to fetch, no additional fetching after data is loaded
  • No runtime magic - no proxies, lazy loading, just data classes containing data fetched from DB
  • Pragmatic - easy to start, but powerful even in not trivial cases (associations, grouping queries)


Given a simple Book class:

data class Book(
   val id: Long? = null,
   val isbn: String,
   val title: String,
   val author: String,
   val publishDate: LocalDate

we can turn it into Krush entity by adding @Entity and @Id annotations:

data class Book(
   @Id @GeneratedValue
   val id: Long? = null,
   val isbn: String,
   val title: String,
   val author: String,
   val publishDate: LocalDate

When we build the project we’ll have BookTable mapping generated for us. So we can persist the Book:

val book = Book(
   isbn = "1449373321", publishDate = LocalDate.of(2017, Month.APRIL, 11),
   title = "Designing Data-Intensive Applications", author = "Martin Kleppmann"

// insert method is generated by Krush
val persistedBook = BookTable.insert(book)

So we have now a Book persisted in DB with autogenerated Book.id field. And now we can use type-safe SQL DSL to query the BookTable:

val bookId = book.id ?: throw IllegalArgumentException()

// toBook method is generated by Krush
val fetchedBook = BookTable.select { BookTable.id eq bookId }.singleOrNull()?.toBook()

// toBookList method is generated by Krush
val selectedBooks = (BookTable)
   .select { BookTable.author like "Martin K%" }




repositories {
    maven { setUrl("https://dl.bintray.com/kotlin/exposed") }
    maven { setUrl("https://philanthropist.touk.pl/nexus/content/repositories/releases") }

apply plugin: 'kotlin-kapt'
api "pl.touk.krush:annotation-processor:$krushVersion"
kapt "pl.touk.krush:annotation-processor:$krushVersion"
api "pl.touk.krush:runtime:$krushVersion"


        <id>Exposed BinTray</id>
        <id>TouK public releases</id>

        <id>Exposed BinTray</id>
        <id>TouK public releases</id>





  • Exposed >= 0.18.1
  • JPA annotations 2.1


  • generates table mappings and functions for mapping from/to data classes
  • type-safe SQL DSL without reading schema from existing database (code-first)
  • explicit association fetching (via leftJoin / innerJoin)
  • multiple data types support
  • custom data type support (with @Converter), also for wrapped auto-generated ids
  • you can still persist associations not directly reflected in domain model (eq. article favorites)

However, Krush is not a full-blown ORM library. This means following JPA features are not supported:

  • lazy association fetching
  • dirty checking
  • caching
  • versioning / optimistic locking


Given following entity:

data class Reservation(
    val uid: UUID = UUID.randomUUID(),

    val status: Status = Status.FREE,

    val reservedAt: LocalDateTime? = null,
    val freedAt: LocalDateTime? = null
) {
    fun reserve() = copy(status = Status.RESERVED, reservedAt = LocalDateTime.now())
    fun free() = copy(status = Status.FREE, freedAt = LocalDateTime.now())

enum class Status { FREE, RESERVED }

you can call Exposed update with generated from metod to overwrite it's data:

val reservation = Reservation().reserve().let(ReservationTable::insert)

val freedReservation = reservation.free()
ReservationTable.update({ ReservationTable.uid eq reservation.uid }) { it.from(freedReservation) }

val updatedReservation = ReservationTable.select({ ReservationTable.uid eq reservation.uid }).singleOrNull()?.toReservation()

For simple cases you can still use Exposed native update syntax:

val freedAt = LocalDateTime.now()
ReservationTable.update({ ReservationTable.uid eq reservation.uid }) {
  it[ReservationTable.status] = Status.FREE
  it[ReservationTable.freedAt] = freedAt

Complete example


@Table(name = "articles")
data class Article(
    @Id @GeneratedValue
    val id: Long? = null,

    @Column(name = "title")
    val title: String,

    @JoinTable(name = "article_tags")
    val tags: List<Tag> = emptyList()

@Table(name = "tags")
data class Tag(
    @Id @GeneratedValue
    val id: Long? = null,

    @Column(name = "name")
    val name: String


val tag1 = Tag(name = "jvm")
val tag2 = Tag(name = "spring")

val tags = listOf(tag1, tag2).map(TagTable::insert)
val article = Article(title = "Spring for dummies", tags = tags)
val persistedArticle = ArticleTable.insert(article)

Querying and fetching

val (selectedArticle) = (ArticleTable leftJoin ArticleTagsTable leftJoin TagTable)
    .select { TagTable.name inList listOf("jvm", "spring") }


Update logic for associations not implemented (yet!) - you have to manually add/remove records from ArticleTagsTable.

Example projects


Special thanks to Łukasz Jędrzejewski for original idea of using Exposed in our projects.


Krush is published under Apache License 2.0.

*Note that all licence references and agreements mentioned in the krush README section above are relevant to that project's source code only.