termyn/cqrs
A lightweight CQRS package for Laravel that separates writes from reads. Route commands and queries through dedicated buses to single-purpose handlers, keeping controllers thin and application logic organized, testable, and easy to extend.
Architecture fit. The package implements CQRS by wrapping Symfony Messenger's command and query buses — commands route to exactly one handler, queries route to exactly one handler, with Messenger's middleware pipeline providing the interception points (validation, transactions, logging). The pattern itself is a reasonable fit for a Laravel codebase that has outgrown fat controllers and service classes, but the implementation is Symfony-native in its assumptions: service registration, handler tagging, and container compilation are the mechanisms a Symfony bundle uses, and none of them map cleanly onto Laravel's Illuminate\Container auto-resolution or package discovery. Expect the architectural cost to be the glue you write, not the package itself.
Integration feasibility. Low to moderate, gated almost entirely by Composer. The stated dependency is symfony/messenger 4.3+, which was released in 2019 and reached end of life years ago. Modern Laravel (10/11) already pins symfony/console, symfony/http-foundation, symfony/process, symfony/error-handler and friends to 6.x/7.x; a hard ^4.3 constraint on Messenger will either fail resolution outright or force a downgrade of the whole framework. If the constraint is permissive (^4.3|^5|^6|^7) the package becomes viable, but that must be verified before anything else. Secondary concerns: handler discovery (Symfony relies on !tagged_iterator; Laravel has no equivalent, so you register handlers explicitly or reflect over the app namespace), no Laravel service provider shipped, and message serialization semantics (envelope stamps, PHP serialize vs. JSON) that differ from what Laravel developers expect from queued jobs.
Technical risk. High. Zero stars and zero dependents is not a vanity metric here — it means no production validation, no Stack Overflow corpus, no third-party blog posts, no one else's bug reports to learn from. Bus factor is one maintainer with no visible succession plan. Security posture is inherited from Messenger 4.3, which no longer receives advisories. The blast radius of an abandoned CQRS bus is large: it sits in the write path of your domain, so a failure surfaces as silently undelivered commands or unhandled messages rather than a loud 500.
Key questions to answer in a spike (timeboxed, ≤2 days):
composer require termyn/cqrs resolve alongside the target Laravel version, and at what cost?ServiceProvider, or is this a Symfony bundle only? (The description says "architecture based on Symfony Messenger," which reads as framework-agnostic core plus a bundle.)php and symfony/messenger constraints in composer.json, and what is the last commit date?Stack fit. Poor as a drop-in for a Laravel-first shop; good only if the organisation already runs Symfony Messenger somewhere and wants a shared vocabulary. For a pure Laravel estate, the honest comparison is Illuminate\Bus\Dispatcher plus ShouldQueue jobs, Illuminate\Contracts\Queue, and Horizon. That gives you queued command-like units with retries, backoff, failure tables, and first-class observability for zero new dependencies. CQRS is a pattern, not a library; the marginal value of this specific package over ~200 lines of internal bus code is small and the ownership cost is real.
Migration path. Do not adopt as a dependency. Fork it into an internal namespace (App\Cqrs or a private Composer package in your registry) under the MIT license, pin the fork, and treat upstream as reference material rather than a supply chain. In the fork: replace Symfony container coupling with Laravel's container, add a ServiceProvider with handler auto-discovery via reflection or attributes, and write contract tests covering dispatch, handler-not-found, and retry behaviour. If the spike shows the core is thin (likely, for a 0-star CQRS wrapper), the cheaper path is to write the abstraction yourself against Illuminate\Bus and skip Symfony Messenger entirely — one queue system instead of two.
Compatibility. This is the hard gate. Verify against a matrix of (PHP 8.1/8.2/8.3) × (Laravel 10/11) × (Messenger 6.4/7.x). Note that upgrading Messenger means the fork drifts from upstream immediately, which is acceptable if you accept ownership. Also validate message serialization across a rolling deploy: if message classes change shape between the producer and consumer versions, in-flight queued messages will fail to hydrate — a classic Messenger failure mode that Laravel job classes mitigate with SerializesModels.
Sequencing.
Maintenance. Effectively 100% internal. Assume the repository is dormant: no issue triage, no PR review, no releases. Budget roughly 10–15% of one senior engineer's time for the first two quarters to own the fork, track Symfony Messenger security releases, and absorb framework-upgrade breakage. If the fork pins Messenger 4.3, you are also carrying an EOL component through every future PHP upgrade — that cost compounds and should be the deciding factor.
Support. No vendor, no SLA, no community. Every incident is a first-principles debugging exercise against unfamiliar internals (envelopes, stamps, middleware stack) with no searchable precedent. Mitigate with a written runbook covering: how to inspect queued commands, how to replay the failure transport, how to hot-fix a deserialization failure, and who is on point.
Scaling. Messenger's transport abstraction is genuinely capable — AMQP, Redis, Doctrine, retry with backoff, failure transport — but only if the fork wires it properly, and in a Laravel shop it introduces a second queue system alongside Horizon/Redis. Two systems means two dashboards, two retry policies, two dead-letter stories, and two sets of worker deployment configs. The domain side scales fine (commands are small, handlers are stateless); the operational surface is what doubles. Plan worker topology, concurrency per transport, and idempotency guarantees before the first production deploy.
Failure modes to design against:
Ramp-up. Moderate to high. A mid-level Laravel developer needs roughly one to two weeks to become productive with CQRS concepts and Messenger internals (envelope, stamps, middleware, buses, transports) — the second half is pure tax that native Laravel tooling would not impose. Add a written ADR and a brown-bag session; otherwise the first team to touch it will either misuse it (business logic in the controller, command as a DTO afterthought) or route around it.
Recommendation. Given zero adoption, zero stars, an EOL upstream dependency, and a Laravel-hostile integration surface, do not adopt this package as a dependency. Run the two-day spike for due diligence, but expect the outcome to be: implement the command/query separation you actually need on top of Illuminate\Bus, or fork this code internally only if the spike proves the Messenger core is a meaningfully better fit than Laravel's native primitives — which, for most Laravel estates, it is not.
How can I help you explore Laravel packages today?