Accepted answer

This is what I do for multiple tables, with slick 3.1.1 and Postgres

import slick.driver.PostgresDriver.api._
import slick.jdbc.meta.MTable
import scala.concurrent.Await
import scala.concurrent.duration.Duration

val t1 = TableQuery[Table1]
val t2 = TableQuery[Table2]
val t3 = TableQuery[Table3]
val tables = List(t1, t2, t3)

val existing =
val f = existing.flatMap( v => {
    val names = =>
    val createIfNotExist = tables.filter( table =>
Await.result(f, Duration.Inf)


cannot use createIfNotExists on schema composed of 3 tables with composite primary key on one of the tables. Here, the 3rd table has a primary key composed from the the primary key of each of the 1st and 2nd table. I get an error on this schema when .createIfNotExists is encountered a 2nd time. I am using slick 3.3.1 on scala 2.12.8.

    class UserTable(tag: Tag) extends Table[User](tag, "user") {
      def id    = column[Long]("id", O.AutoInc, O.PrimaryKey)
      def name  = column[String]("name")
      def email = column[Option[String]]("email")

      def * = (id.?, name, email).mapTo[User]
    val users = TableQuery[UserTable]
    lazy val insertUser = users returning

    case class Room(title: String, id: Long = 0L)
    class RoomTable(tag: Tag) extends Table[Room](tag, "room") {
     def id    = column[Long]("id", O.PrimaryKey, O.AutoInc)
     def title = column[String]("title")
     def * = (title, id).mapTo[Room]
    val rooms = TableQuery[RoomTable]
    lazy val insertRoom = rooms returning

    case class Occupant(roomId: Long, userId: Long)
    class OccupantTable(tag: Tag) extends Table[Occupant](tag, "occupant") {
      def roomId = column[Long]("room")
      def userId = column[Long]("user")

      def pk = primaryKey("room_user_pk", (roomId, userId) )

      def * = (roomId, userId).mapTo[Occupant]
    val occupants = TableQuery[OccupantTable]

I can successfully create schema and add user, room and occupant at first. On the second usage of .createIfNotExists as follows below, I get an error on duplicate primary key:

  println("\n2nd run on .createIfNotExists using different values for users, rooms and occupants")
  val initdup = for {
    _         <- users.schema.createIfNotExists
    _         <- rooms.schema.createIfNotExists
    _         <- occupants.schema.createIfNotExists
      curlyId   <- insertUser += User(None, "Curly", Some(""))
      larryId   <- insertUser += User(None, "Larry")
      moeId     <- insertUser += User(None, "Moe", Some(""))
      shedId   <- insertRoom += Room("Shed")
      _         <- occupants += Occupant(shedId, curlyId)
      _         <- occupants += Occupant(shedId, moeId)
    } yield ()

The exception is as below:

2nd run on .createIfNotExists using different values for users, rooms and occupants
[error] (run-main-2) org.h2.jdbc.JdbcSQLException: Constraint "room_user_pk" already exists; SQL statement:
[error] alter table "occupant" add constraint "room_user_pk" primary key("room","user") [90045-197]
[error] org.h2.jdbc.JdbcSQLException: Constraint "room_user_pk" already exists; SQL statement:
[error] alter table "occupant" add constraint "room_user_pk" primary key("room","user") [90045-197]
[error]         at org.h2.message.DbException.getJdbcSQLException(
[error]         at org.h2.message.DbException.get(
[error]         at org.h2.message.DbException.get(
[error]         at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(
[error]         at org.h2.command.ddl.AlterTableAddConstraint.update(
[error]         at org.h2.command.CommandContainer.update(
[error]         at org.h2.command.Command.executeUpdate(
[error]         at org.h2.jdbc.JdbcPreparedStatement.execute(
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$6.$anonfun$run$7(JdbcActionComponent.scala:292)
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$6.$anonfun$run$7$adapted(JdbcActionComponent.scala:292)
[error]         at slick.jdbc.JdbcBackend$SessionDef.withPreparedStatement(JdbcBackend.scala:425)
[error]         at slick.jdbc.JdbcBackend$SessionDef.withPreparedStatement$(JdbcBackend.scala:420)
[error]         at slick.jdbc.JdbcBackend$BaseSession.withPreparedStatement(JdbcBackend.scala:489)
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$6.$anonfun$run$6(JdbcActionComponent.scala:292)
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$6.$anonfun$run$6$adapted(JdbcActionComponent.scala:292)
[error]         at scala.collection.Iterator.foreach(Iterator.scala:941)
[error]         at scala.collection.Iterator.foreach$(Iterator.scala:941)
[error]         at scala.collection.AbstractIterator.foreach(Iterator.scala:1429)
[error]         at scala.collection.IterableLike.foreach(IterableLike.scala:74)
[error]         at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
[error]         at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$
[error]         at slick.jdbc.JdbcActionComponent$SchemaActionExtensionMethodsImpl$$anon$
[error]         at slick.jdbc.JdbcActionComponent$
[error]         at slick.jdbc.JdbcActionComponent$
[error]         at slick.basic.BasicBackend$DatabaseDef$$anon$3.liftedTree1$1(BasicBackend.scala:276)
[error]         at slick.basic.BasicBackend$DatabaseDef$$anon$
[error]         at java.util.concurrent.ThreadPoolExecutor.runWorker(
[error]         at java.util.concurrent.ThreadPoolExecutor$
[error]         at
[error] Nonzero exit code: 1
[error] (Compile / run) Nonzero exit code: 1

Additionally, I can use .createIfNotExists more than once on schema where all tables are created with O.PrimaryKey convention.

Am I able to do something to massage code? Is there a workaround so that .createIfNotExists is still usable on composite primary key case?


why don't you simply check the existence before create?

val schema = coffees.schema ++ suppliers.schema
  if (!MTable.getTables.list.exists( == MyTable.tableName)){


As JoshSGoman comment points out about the answer of Mike-s, the table is not created. I managed to make it work by slightly modifying the first answer's code :

val coffees = TableQuery[Coffees]

try {
  def createTableIfNotInTables(tables: Vector[MTable]): Future[Unit] = {
    if (!tables.exists( == events.baseTableRow.tableName)) {
    } else {

  val createTableIfNotExist: Future[Unit] =

  Await.result(createTableIfNotExist, Duration.Inf)
} finally db.close

With the following imports :

import slick.jdbc.meta.MTable
import slick.driver.SQLiteDriver.api._

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration


With Slick 3.0, Mtable.getTables is a DBAction so something like this would work:

val coffees = TableQuery[Coffees]
try {
    MTable.getTables map (tables => {
      if (!tables.exists( == coffees.baseTableRow.tableName))
  )), Duration.Inf)
} finally db.close


In Slick 3.3.0 createIfNotExists and dropIfExists schema methods were added. So:

Googled this question and tried several solutions from answers until figured it out.

Related Query

More Query from same tag