Using DBOS with Kotlin
DBOS works with Kotlin out of the box — all Java APIs are accessible from Kotlin.
The transact artifact also ships Kotlin extension functions that make the most common calls idiomatic by placing the lambda last, enabling Kotlin's trailing lambda syntax.
Dependency
The Kotlin extensions are included in the main transact artifact alongside the Java code; no extra dependency is needed.
- Gradle
- Maven
dependencies {
implementation("dev.dbos:transact:0.8.0")
}
<dependencies>
<dependency>
<groupId>dev.dbos</groupId>
<artifactId>transact</artifactId>
<version>0.8.0</version>
</dependency>
</dependencies>
Writing Workflows and Steps
Define your interface and implementation exactly as you would in Java, using the same @Workflow annotation:
interface OrderService {
fun processOrder(orderId: String): String
}
class OrderServiceImpl(private val dbos: DBOS) : OrderService {
private lateinit var self: OrderService
fun setSelf(proxy: OrderService) { self = proxy }
@Workflow
override fun processOrder(orderId: String): String {
val result = dbos.runStep("fetchOrder") {
fetchFromApi(orderId) // trailing lambda — idiomatic Kotlin
}
dbos.runStep("saveOrder") {
saveToDatabase(result)
}
return result
}
}
The dbos.runStep(name) { ... } form is a Kotlin extension function that puts the lambda last, avoiding the ThrowingSupplier wrapping you'd need in Java.
Starting Workflows
Use dbos.startWorkflow(options) { ... } with trailing lambda syntax:
val dbos = DBOS(config)
val service = dbos.registerProxy(OrderService::class.java, OrderServiceImpl(dbos))
dbos.launch()
// Start a workflow in the background
val handle = dbos.startWorkflow(StartWorkflowOptions()) {
service.processOrder("order-123")
}
// Or with a specific workflow ID
val handle = dbos.startWorkflow(StartWorkflowOptions("my-workflow-id")) {
service.processOrder("order-456")
}
val result = handle.result
Kotlin's SAM conversion means a plain dbos.startWorkflow { } call (with no options argument) would be ambiguous with the Java overload.
Always pass StartWorkflowOptions() (or null) as the first argument when using the trailing lambda form.
Step Options
Pass a StepOptions object when you need retry configuration:
val result = dbos.runStep(StepOptions("fetchOrder").withMaxAttempts(3)) {
fetchFromApi(orderId)
}
Registration and Lifecycle
Registration and lifecycle are identical to Java:
val config = DBOSConfig.defaultsFromEnv("my-app")
val dbos = DBOS(config)
val service = dbos.registerProxy(OrderService::class.java, OrderServiceImpl(dbos).also {
it.setSelf(/* proxy set below */)
})
dbos.launch()
// DBOS is AutoCloseable
dbos.use {
service.processOrder("order-789")
}