Scala Days is the primary conference for the Scala ecosystem, covering JVM performance, functional programming, distributed systems, and tooling. The 2025 edition included sessions on identifier design for distributed Scala applications, with significant focus on UUID v7 as a replacement for auto-increment sequences in event-sourced systems. Presenters covered the uuid-creator library on Maven Central, Slick and Doobie database integration, and Cats Effect patterns for referentially transparent ID generation.
UUID v7 in Scala — basic generation
import com.github.f4b6a3.uuid.UuidCreator
// UUID v7 with monotonic counter (RFC 9562 Method 1)
val id: java.util.UUID = UuidCreator.getTimeOrderedEpoch()
// Convert to string
val idStr: String = id.toString
// e.g. "019236a7-b4f2-7000-8d3e-9c1a2b3d4e5f"
// Extract timestamp
val tsMs: Long = id.getMostSignificantBits >>> 16
The getTimeOrderedEpoch() method generates UUID v7 values with a monotonic counter for within-millisecond ordering — important for event-sourced systems where many events may be created in a single millisecond.
Referentially transparent generation with Cats Effect
In functional Scala, side-effecting operations like UUID generation should be wrapped in an effect type:
import cats.effect.IO
import com.github.f4b6a3.uuid.UuidCreator
def generateId(): IO[java.util.UUID] =
IO(UuidCreator.getTimeOrderedEpoch())
// Compose in for-comprehension
val program: IO[Unit] = for {
orderId <- generateId()
lineId <- generateId()
_ <- IO.println(s"Order $orderId, Line $lineId")
} yield ()
Wrapping in IO makes UUID generation mockable in tests — inject a deterministic generator in test environments. The Cats Effect documentation covers IO semantics and referential transparency.
Doobie integration (PostgreSQL)
import doobie._
import doobie.implicits._
import java.util.UUID
// Doobie maps java.util.UUID to PostgreSQL uuid type natively
def insertOrder(id: UUID, customerId: UUID, total: BigDecimal): Update0 =
sql"""
INSERT INTO orders (id, customer_id, total)
VALUES ($id, $customerId, $total)
""".update
// Usage
val id = UuidCreator.getTimeOrderedEpoch()
insertOrder(id, customerId, BigDecimal("99.99"))
.run.transact(xa).unsafeRunSync()
Doobie handles java.util.UUID natively for PostgreSQL uuid columns. No custom mapping is needed — pass UUID v7 values directly.
Slick integration
import slick.jdbc.PostgresProfile.api._
import java.util.UUID
import com.github.f4b6a3.uuid.UuidCreator
class OrdersTable(tag: Tag) extends Table[Order](tag, "orders") {
def id = column[UUID]("id", O.PrimaryKey)
def customerId = column[UUID]("customer_id")
def * = (id, customerId) <> (Order.tupled, Order.unapply)
}
// Insert with UUID v7 primary key
val newOrder = Order(
id = UuidCreator.getTimeOrderedEpoch(),
customerId = existingCustomerId
)
The Slick documentation covers PostgreSQL profile configuration and UUID column mapping.
Event sourcing with UUID v7 event IDs
In event-sourced systems, UUID v7 event IDs replace sequence numbers:
case class OrderEvent(
eventId: java.util.UUID, // UUID v7 — encodes when event occurred
orderId: java.util.UUID, // UUID v4 or v7 — the aggregate root
eventType: String,
payload: String
)
// Events can be ordered by eventId without a separate sequence column
val events: List[OrderEvent] = loadEvents(orderId)
val sorted: List[OrderEvent] = events.sortBy(_.eventId.toString)
UUID v7 replaces the sequence_number BIGSERIAL column in event store schemas. The sort order is guaranteed by the RFC 9562 §5.7 time-ordering property.
Akka Persistence entity IDs
import akka.actor.typed.ActorSystem
import akka.persistence.typed.PersistenceId
// Use UUID v7 for persistent actor entity IDs
val entityId = UuidCreator.getTimeOrderedEpoch().toString
val persistenceId = PersistenceId.ofUniqueId(entityId)
Entity IDs in Akka Persistence are string-typed. Using UUID v7 means entity IDs encode creation time — useful for sharding entities by time range across projection shards. The Akka Persistence documentation covers entity ID design patterns.
Further reading
- UUID in Databases — PostgreSQL, MySQL storage patterns
- UUID v7 in Distributed Systems — ordering and event correlation
- Monotonic Counter — within-millisecond ordering
External references
- uuid-creator on GitHub
- uuid-creator on Maven Central
- Doobie — functional JDBC for Scala
- Cats Effect documentation
- RFC 9562 — UUID standard
Frequently asked questions
What is the best library for UUID v7 in Scala or Java?
uuid-creator is the most complete JVM UUID library — it implements all RFC 9562 versions including v7 with a monotonic counter, and is available on Maven Central. For Scala-idiomatic UUID handling, Cats Effect users can wrap generation in IO for referential transparency. Java 9+ UUID generation with UUID.randomUUID() produces v4 only — use uuid-creator for v7.
How do I use UUID v7 as a Slick primary key in Scala?
Define a custom BaseColumnType[UUID] mapping and use UuidCreator.getTimeOrderedEpoch as the default: def id = column[UUID]("id", O.PrimaryKey, O.Default(UuidCreator.getTimeOrderedEpoch)). The Slick schema documentation covers custom column types and default values. PostgreSQL's uuid column type stores the value in 16 bytes regardless of which version is used.
Does UUID v7 work with Akka cluster member IDs?
Akka cluster node addresses use a host:port:uid format where uid is a random integer — not a UUID. You can use UUID v7 for application-level entity IDs (persistent actor IDs in Akka Persistence, Durable State IDs) without affecting cluster membership. The Akka Persistence documentation shows how to use UUID strings as persistent entity IDs.