Sitemap
manzarul haque

manzarul haque

Transactional Outbox Pattern

3 min readOct 26, 2026

--

Press enter or click to view image in full size

What is the Transactional Outbox Pattern?

The Transactional Outbox Pattern ensures that a database change and the event associated with it are saved reliably in the same database transaction.

It solves a common problem in microservices: what happens if the database update succeeds but publishing the event to Kafka fails?

The problem

Consider an order service that saves an order and publishes an OrderCreated event.

@Transactional
public Order createOrder(Order order) {
Order savedOrder = orderRepository.save(order);
kafkaTemplate.send("order-created", savedOrder);
return savedOrder;
}

If the database transaction succeeds but Kafka is unavailable, the order is saved, but other services never receive the event.

The database transaction does not automatically include the Kafka operation.

How does the Outbox Pattern solve it?

Instead of publishing the event directly, save it in an outbox table within the same database transaction.

@Transactional
public Order createOrder(Order order) {
Order savedOrder = orderRepository.save(order);
outboxRepository.save(
new OutboxEvent("OrderCreated", savedOrder.getId())
);
return savedOrder;
}

A separate publisher reads events from the outbox table and publishes them to Kafka.

Order Service
|
v
Save Order + Outbox Event
|
v
Same Database Transaction
|
v
Outbox Publisher
|
v
Kafka
|
v
Other Microservices

If the transaction fails, both database changes are rolled back. If Kafka is unavailable, the event remains in the outbox and can be published later.

Get manzarul haque’s stories in your inbox

Join Medium for free to get updates from this writer.

In production, the publisher must handle retries, duplicate events, and concurrent processing.

What are the alternatives?

The Outbox Pattern is not the only way to solve this problem. The right approach depends on your application’s requirements.

1. Event-Driven Architecture (EDA)

Instead of directly calling other services, publish an event such as OrderReceived. Other services consume the event and perform their own processing.

For example:

Order Received
|
v
Order Service
|
v
Order Created
|
v
Payment Processing
|
v
Payment Completed
|
v
Order Booked
|
v
Inventory / Notification

This approach reduces direct dependencies between services and allows each service to process events independently.

But EDA alone does not solve the database-and-event consistency problem. If the order is saved but publishing OrderReceived fails, the original problem still exists.

You can combine EDA with the Outbox Pattern to achieve both loose coupling and reliable event publishing.

2. Database transaction + message broker transaction

Some messaging systems support transactions that cover message publishing and consumption. Kafka also supports transactions for Kafka records.

However, a regular database transaction and a Kafka transaction are not automatically one atomic transaction. Coordinating both generally requires additional mechanisms, such as distributed transactions, where supported.

This approach can add complexity and is not always suitable for microservices.

3. Change Data Capture (CDC)

Tools such as Debezium can read database changes from the transaction log and publish corresponding events to Kafka.

With the Outbox Pattern, the application saves the event to the outbox table, and CDC publishes it without requiring a scheduled polling process.

This is useful when you need reliable event delivery at higher throughput.

Final thoughts

EDA defines how services communicate through events. The Transactional Outbox Pattern ensures that a service does not lose an event when its database update succeeds but event publishing fails.

They are not competing approaches. For an order-processing system, combining EDA with the Outbox Pattern is often a good choice: save the order and OrderReceived event in one transaction, publish the event reliably, and let downstream services generate events such as PaymentCompleted and OrderBooked as processing progresses.

--

--