Documentation • Examples • Github • Discord
DBOS provides lightweight durable workflows built on top of Postgres. Essentially, it helps you write long-lived, reliable code that can survive crashes, restarts, and failures without losing state or duplicating work.
As your workflows run, DBOS checkpoints each step they take in a Postgres database. When a process stops (fails, intentionally suspends, or a machine dies), your program can recover from those checkpoints to restore its exact state and continue from where it left off, as if nothing happened.
In practice, this makes it easier to build reliable systems for use cases like AI agents, payments, data synchronization, or anything that takes minutes, days, or weeks to complete. Rather than bolting on ad-hoc retry logic and database checkpoints, durable workflows give you one consistent model for ensuring progress without duplicate execution.
This library contains all you need to add durable workflows to your program: there's no separate service or orchestrator or any external dependencies except Postgres. Because it's just a library, you can incrementally add it to your projects, and it works out of the box with frameworks like Spring. And because it's built on Postgres, it natively supports all the tooling you're familiar with (backups, GUIs, CLI tools) and works with any Postgres provider.
💾 Durable Workflows
Workflows make your program durable by checkpointing its state in Postgres. If your program ever fails, when it restarts all your workflows will automatically resume from the last completed step.
You add durable workflows to your existing Java program in just a few lines of code by registering ordinary functions as workflows and steps:
interface Example {
public void workflow();
}
class ExampleImpl implements Example {
private void stepOne() {
System.out.println("Step one completed!");
}
private void stepTwo() {
System.out.println("Step two completed!");
}
@Workflow()
public void workflow() {
DBOS.runStep(() -> stepOne(), "stepOne");
DBOS.runStep(() -> stepTwo(), "stepTwo");
}
}Workflows are particularly useful for
- Orchestrating business processes so they seamlessly recover from any failure.
- Building observable and fault-tolerant data pipelines.
- Operating an AI agent, or any application that relies on unreliable or non-deterministic APIs.
📒 Asynchronous execution
DBOS can run your workflows asynchronously without you needing to make any changes to the interface or implementation.
This is ideal for long-running workflows whose result might not be available immediately. You code can return at a later point and check the status for completion and/or retrive the result.
var handle = DBOS.startWorkflow(()->example.exampleWorkflow("HelloDBOS"));
result = handle.getResult();📒 Durable Queues
DBOS queues help you durably run tasks in the background. You can enqueue a task (which can be a single step or an entire workflow) from a durable workflow and one of your processes will pick it up for execution. DBOS manages the execution of your tasks: it guarantees that tasks complete, and that their callers get their results without needing to resubmit them, even if your application is interrupted.
Queues also provide flow control, so you can limit the concurrency of your tasks on a per-queue or per-process basis. You can also set timeouts for tasks, rate limit how often queued tasks are executed, deduplicate tasks, or prioritize tasks.
You can add queues to your workflows in just a couple lines of code. They don't require a separate queueing service or message broker—just Postgres.
public void queuedTasks() {
var q = new Queue("childQ");
DBOS.registerQueue(q);
DBOS.launch();
for (int i = 0; i < 3; i++) {
String workflowId = "child" + i;
var options = new StartWorkflowOptions(workflowId).withQueue(q);
List<WorkflowHandle<String>> handles = new ArrayList<>();
handles.add(DBOS.startWorkflow(()->simpleService.childWorkflow(workflowId), options));
}
for (int i = 0 ; i < 3 ; i++) {
String workflowId = "child"+i;
var h = DBOS.retrieveWorkflow(workflowId);
System.out.println(h.getResult());
}
}📅 Durable Scheduling
Schedule workflows using cron syntax, or use durable sleep to pause workflows for as long as you like (even days or weeks) before executing.
You can schedule a workflow using a single annotation:
public class SchedulerImpl implements Scheduler {
@Workflow(name = "every5Second")
@Scheduled(cron = "0/5 * * * * ?")
public void every5Second(Instant schedule , Instant actual) {
log.info("Executed workflow "+ schedule.toString() + " " + actual.toString()) ;
}
}
// In your main
DBOS.registerWorkflows(Scheduler.class, new SchedulerImpl());📫 Durable Notifications
Pause your workflow executions until a notification is received, or emit events from your workflow to send progress updates to external clients. All notifications are stored in Postgres, so they can be sent and received with exactly-once semantics. Set durable timeouts when waiting for events, so you can wait for as long as you like (even days or weeks) through interruptions or restarts, then resume once a notification arrives or the timeout is reached.
For example, build a reliable billing workflow that durably waits for a notification from a payments service, processing it exactly-once:
@Workflow(name = "billing")
public void billingWorkflow() {
// Calculate the charge, then submit the bill to a payments service
String paymentStatus = (String) DBOS.recv(PAYMENT_STATUS, paymentServiceTimeout);
if (paymentStatus.equals("paid")) {
// handle paid
} else {
// handle not paid
}
}
@Workflow(name = "payment")
public void payment(String targetWorkflowId) {
DBOS.send(targetWorkflowId, PAYMENT_STATUS, "paid") ;
}
To get started, follow the quickstart to install this open-source library and connect it to a Postgres database. Then, check out the programming guide to learn how to build with durable workflows and queues.
https://docs.dbos.dev/examples
DBOS vs. Temporal
Both DBOS and Temporal provide durable execution, but DBOS is implemented in a lightweight Postgres-backed library whereas Temporal is implemented in an externally orchestrated server.
You can add DBOS to your program by installing this open-source library, connecting it to Postgres, and registering workflows and steps. By contrast, to add Temporal to your program, you must rearchitect your program to move your workflows and steps (activities) to a Temporal worker, configure a Temporal server to orchestrate those workflows, and access your workflows only through a Temporal client. This blog post makes the comparison in more detail.
When to use DBOS: You need to add durable workflows to your applications with minimal rearchitecting, or you are using Postgres.
When to use Temporal: You don't want to add Postgres to your stack, or you need a language DBOS doesn't support yet.
If you want to ask questions or hang out with the community, join us on Discord! If you see a bug or have a feature request, don't hesitate to open an issue here on GitHub. If you're interested in contributing, check out our contributions guide.