PHPackages                             bugfix666/laravel-outbox - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. bugfix666/laravel-outbox

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

bugfix666/laravel-outbox
========================

Transactional Outbox pattern for Laravel

v1.0.1(today)00GPL-3.0-onlyPHPPHP ^8.4CI passing

Since Jun 22Pushed todayCompare

[ Source](https://github.com/bugfix666/laravel-outbox)[ Packagist](https://packagist.org/packages/bugfix666/laravel-outbox)[ RSS](/packages/bugfix666-laravel-outbox/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (3)Versions (2)Used By (0)

Laravel Outbox
==============

[](#laravel-outbox)

[![Latest Version on Packagist](https://camo.githubusercontent.com/22fc09dd03e9e0b97e558e17348792996e71f07ea48cbe9a1e23aa34c4ffacae/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6275676669783636362f6c61726176656c2d6f7574626f782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bugfix666/laravel-outbox)[![PHP Version](https://camo.githubusercontent.com/2e7d3fc3e086a733674b39c46ed784a06a0ed1b7c469ccdbf4a30fbe82344326/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6275676669783636362f6c61726176656c2d6f7574626f782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bugfix666/laravel-outbox)[![Laravel Version](https://camo.githubusercontent.com/19d5bb0370853f3f5f64da8e47f7b2e14803b7fa5f7c8d04e347ac6849edb9ee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31322e782d7265642e7376673f7374796c653d666c61742d737175617265)](https://laravel.com)[![License](https://camo.githubusercontent.com/0c0f819e02f816104150c3e47052232458eed302067b4da6c8e36eb4ae1f6cd2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6275676669783636362f6c61726176656c2d6f7574626f782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bugfix666/laravel-outbox)![PHP](https://camo.githubusercontent.com/25012e98b640e282284d84348b9c496c315c270928666c27e504e5fa10802102/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342b2d3737374242343f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)[![Run Tests](https://github.com/bugfix666/laravel-outbox/actions/workflows/tests.yml/badge.svg)](https://github.com/bugfix666/laravel-outbox/actions/workflows/tests.yml)[![Total Downloads](https://camo.githubusercontent.com/5eb46196c0a98d3e4290e3ab5a8e04e2bfd0a846784852e50c9586d18123e715/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6275676669783636362f6c61726176656c2d6f7574626f782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bugfix666/laravel-outbox)

**Transactional Outbox pattern implementation for Laravel 12+ (PHP 8.4+).**
Guarantees atomicity and reliable event delivery in distributed systems, especially fintech, e‑commerce, and microservices.

---

### 📊 Comparison with Existing Solutions

[](#-comparison-with-existing-solutions)

There are several open‑source implementations of the Transactional Outbox pattern for Laravel. Here’s how **laravel-outbox** compares to them:

Feature**This Package**[webrek/laravel-outbox](https://github.com/webrek/laravel-outbox)[GaiPalyan/laravel-outbox](https://github.com/GaiPalyan/laravel-outbox)[Dnakitare/laravel-outbox](https://github.com/Dnakitare/laravel-outbox)**PHP Version****8.4+**8.1+8.1+8.2+**Laravel Version****12+**10+10+10 – 12**PHP 8.4 Features** (typed properties, readonly, attributes)✅ Full❌❌❌**Production‑ready**✅ Yes✅ Yes✅ Yes⚠️ Beta (0.1.0-beta1)**Strict Typing**✅ Yes———**Unit &amp; Feature Tests**✅ 15 tests❌❌✅ (limited)**Dead Letter Queue (DLQ)**✅ Yes❌❌✅ Yes**Inbox Pattern**❌ (outbox only)❌✅❌**Event / Job Interception**❌ (explicit control)❌❌✅ (auto‑intercepts)**Atomicity**✅ (single DB transaction)✅✅✅**Custom Publishers**✅ (via contract)✅✅—**Retry Logic**✅ (exponential backoff)✅✅✅**Worker Locking**✅ (prevents parallel runs)✅❌—**Cleanup Command**✅ (`outbox:cleanup`)✅✅✅**Monitoring Events**✅ (`Processed` / `Failed`)✅❌—---

### 🚀 Why This Package Stands Out

[](#-why-this-package-stands-out)

1. **Cutting‑Edge Stack** – Built specifically for PHP 8.4+ and Laravel 12+, leveraging the latest language features for cleaner, safer, and more maintainable code.
2. **Production‑Ready** – Unlike some alternatives that are still in beta, this package is fully tested (15+ unit and feature tests) and ready for mission‑critical applications.
3. **Dead Letter Queue (DLQ)** – Failed messages after all retries are not lost. They remain in the outbox table for inspection and manual intervention – essential for fintech and reliability‑first systems.
4. **Explicit Control, No Magic** – Unlike packages that automatically intercept all events/jobs, this package gives you full control over what and when to publish. No surprises, easier debugging, and predictable behavior.
5. **Built‑in Monitoring** – The `OutboxMessageProcessed` and `OutboxMessageFailed` events allow seamless integration with logging, metrics (Prometheus, StatsD), and alerting.
6. **Strict Typing &amp; Modern Practices** – Readonly classes, typed properties, constructor property promotion, and console command attributes make the code self‑documenting and robust.

---

**If you need a reliable, modern, and transparent outbox implementation for your fintech or distributed system – this package is the best choice among all existing open‑source solutions.**

---

📦 Features
----------

[](#-features)

- ✅ **Atomic persistence** – business data + outbox record in a single DB transaction.
- ✅ **Reliable background processing** – worker with locking, batch processing, and retries.
- ✅ **Flexible publishers** – log, queue, or your own (Kafka, RabbitMQ, SNS, etc.).
- ✅ **Built‑in retry logic** – exponential backoff (configurable attempts &amp; delay).
- ✅ **Monitoring** – events for processed/failed messages; easy to integrate with logging or metrics.
- ✅ **Cleanup** – automated purging of old processed messages.
- ✅ **Modern PHP 8.4+** – typed properties, readonly classes, enums, constructor promotion.
- ✅ **Laravel 12+ ready** – uses new attribute‑based console commands.

---

🔧 Requirements
--------------

[](#-requirements)

- PHP 8.4 or higher
- Laravel 12.0 or higher
- Database that supports transactions (MySQL, PostgreSQL, SQLite, etc.)

---

📥 Installation
--------------

[](#-installation)

```
composer require bugfix666/laravel-outbox
```

---

🚀 Setup
-------

[](#-setup)

Publish the configuration and migration files:

```
php artisan vendor:publish --tag=outbox-config
php artisan vendor:publish --tag=outbox-migrations
```

Run the migration to create the `outbox_messages` table:

```
php artisan migrate
```

---

⚙️ Configuration
----------------

[](#️-configuration)

The config file `config/outbox.php` allows you to tailor the package to your needs:

```
return [
    'table'      => env('OUTBOX_TABLE', 'outbox_messages'),
    'connection' => env('OUTBOX_DB_CONNECTION', env('DB_CONNECTION', 'mysql')),

    // Your custom publisher class (must implement OutboxPublisher)
    'publisher'  => env('OUTBOX_PUBLISHER', Bugfix666\LaravelOutbox\Publishers\LogPublisher::class),

    'worker' => [
        'batch_size'   => env('OUTBOX_BATCH_SIZE', 100),
        'lock_timeout' => env('OUTBOX_LOCK_TIMEOUT', 10), // seconds
        'lock_store'   => env('OUTBOX_LOCK_STORE', 'cache'), // cache, redis, etc.
    ],

    'cleanup' => [
        'days' => env('OUTBOX_CLEANUP_DAYS', 7),
    ],

    'retry' => [
        'max_attempts'   => env('OUTBOX_MAX_ATTEMPTS', 5),
        'delay_seconds'  => env('OUTBOX_RETRY_DELAY', 60), // seconds between attempts
    ],
];
```

Set your preferred publisher in `.env`:

```
OUTBOX_PUBLISHER=App\Publishers\KafkaPublisher
OUTBOX_BATCH_SIZE=50
OUTBOX_MAX_ATTEMPTS=3
```

---

💡 Basic Usage
-------------

[](#-basic-usage)

### 1. Store an outbox message inside a transaction

[](#1-store-an-outbox-message-inside-a-transaction)

```
use Bugfix666\LaravelOutbox\Services\OutboxService;
use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($outboxService) {
    // 1. Business logic (e.g., create a payment)
    $payment = Payment::create([
        'amount' => 1000,
        'currency' => 'USD',
        'status' => 'completed',
    ]);

    // 2. Store the outbox message – guaranteed to be persisted atomically
    $outboxService->store(
        aggregateType: 'Payment',
        aggregateId: (string) $payment->id,
        eventType: 'payment.completed',
        payload: [
            'payment_id' => $payment->id,
            'amount' => $payment->amount,
            'user_id' => auth()->id(),
        ]
    );
});
```

### 2. Run the worker

[](#2-run-the-worker)

Start the outbox processor (should be supervised in production):

```
php artisan outbox:process
```

You can override batch size on the fly:

```
php artisan outbox:process --batch-size=200
```

### 3. Clean up old processed messages

[](#3-clean-up-old-processed-messages)

Schedule the cleanup command to run daily (in `routes/console.php`):

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('outbox:cleanup')->daily();
```

Or run manually:

```
php artisan outbox:cleanup --days=14
```

---

🔌 Custom Publisher
------------------

[](#-custom-publisher)

By default, the package logs events. To send events to a real broker, create a class that implements `Bugfix666\LaravelOutbox\Contracts\OutboxPublisher`:

```
namespace App\Publishers;

use Bugfix666\LaravelOutbox\Contracts\OutboxPublisher;
use RdKafka\Producer;

class KafkaPublisher implements OutboxPublisher
{
    public function __construct(private Producer $producer) {}

    public function publish(string $eventType, array $payload, ?string $aggregateId = null): bool
    {
        $topic = $this->producer->newTopic($eventType);
        $topic->produce(RD_KAFKA_PARTITION_UA, 0, json_encode($payload));
        $this->producer->flush(1000);
        return true;
    }
}
```

Then set `OUTBOX_PUBLISHER=App\Publishers\KafkaPublisher` in your `.env`.

> **Tip:** For RabbitMQ, use `php-amqplib`; for AWS SNS, use the Laravel SNS facade.

---

🧩 Monitoring and Events
-----------------------

[](#-monitoring-and-events)

The package fires two events that you can listen to:

- `Bugfix666\LaravelOutbox\Events\OutboxMessageProcessed`
- `Bugfix666\LaravelOutbox\Events\OutboxMessageFailed`

Example listener:

```
use Bugfix666\LaravelOutbox\Events\OutboxMessageFailed;

class LogOutboxFailure
{
    public function handle(OutboxMessageFailed $event): void
    {
        logger()->error('Outbox failure', [
            'id' => $event->message->id,
            'attempts' => $event->message->attempts,
            'error' => $event->exception->getMessage(),
        ]);
    }
}
```

Register your listener in `EventServiceProvider`.

---

🔄 Retry Logic
-------------

[](#-retry-logic)

When publishing fails, the worker increments the `attempts` counter and sets `available_at` to `now() + delay_seconds`. The next run will only pick messages where `available_at` is in the past, giving the broker time to recover.

After `max_attempts` failures, the message remains unprocessed but is considered failed – you can handle it manually or set up an alert.

---

🧪 Testing
---------

[](#-testing)

The package is fully testable. You can mock the publisher and assert that messages are stored and processed correctly.

Example test:

```
public function test_message_is_stored(): void
{
    DB::transaction(function () {
        $service = app(OutboxService::class);
        $message = $service->store('User', '123', 'user.created', ['name' => 'John']);
        $this->assertDatabaseHas('outbox_messages', ['id' => $message->id]);
    });
}
```

---

📊 Performance Considerations
----------------------------

[](#-performance-considerations)

- **Indexes** – The migration includes indexes on `(processed_at, created_at)`, `aggregate_type/aggregate_id`, and `available_at` to keep queries fast.
- **Batch size** – Tune `batch_size` according to your workload. Larger batches reduce DB round‑trips but increase memory usage.
- **Partitioning** – For extremely high volume, consider table partitioning by `created_at` (e.g., daily) to keep the active set small.
- **Locking** – The worker uses `FOR UPDATE` to prevent double‑processing. Ensure your database supports row‑level locking.

---

🛠 Supervisor Configuration
--------------------------

[](#-supervisor-configuration)

For production, keep the worker running with Supervisor:

```
[program:outbox-worker]
command=php /path/to/your/project/artisan outbox:process
directory=/path/to/your/project
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/path/to/your/project/storage/logs/outbox-worker.log
```

---

📖 Full Documentation
--------------------

[](#-full-documentation)

- [Transactional Outbox Pattern – Martin Fowler](https://martinfowler.com/eaaDev/Outbox.html)
- [Laravel 12 Documentation](https://laravel.com/docs/12.x)

---

🤝 Contributing
--------------

[](#-contributing)

1. Fork the repository.
2. Create a feature branch (`git checkout -b feature/amazing-feature`).
3. Commit your changes (`git commit -m 'Add some amazing feature'`).
4. Push to the branch (`git push origin feature/amazing-feature`).
5. Open a Pull Request.

Please ensure that your code passes the existing tests and is well‑documented.

---

📝 License
---------

[](#-license)

This package is open‑source software licensed under the [MIT license](https://opensource.org/licenses/MIT).

---

💬 Support
---------

[](#-support)

For questions, bug reports, or feature requests, please [open an issue](https://github.com/bugfix666/laravel-outbox/issues) on GitHub.

---

**Happy coding, and may your events always be delivered! 🚀**

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/60221974?v=4)[softinvest](/maintainers/softinvest)[@softinvest](https://github.com/softinvest)

---

Top Contributors

[![bugfix666](https://avatars.githubusercontent.com/u/151177991?v=4)](https://github.com/bugfix666 "bugfix666 (6 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/bugfix666-laravel-outbox/health.svg)

```
[![Health](https://phpackages.com/badges/bugfix666-laravel-outbox/health.svg)](https://phpackages.com/packages/bugfix666-laravel-outbox)
```

###  Alternatives

[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17818.7k](/packages/markwalet-nova-modal-response)[crumbls/layup

A visual page builder plugin for Filament 5 — Divi-style grid layouts with extensible widgets.

591.7k1](/packages/crumbls-layup)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

119.2k](/packages/tomshaw-electricgrid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
