laravel/horizon
Laravel Horizon provides a beautiful dashboard and code-driven configuration for Redis queues, letting you monitor job throughput, runtime, and failures while keeping worker settings in source control.
Architecture fit. Horizon is a first-party Laravel package, which is the single most important architectural fact about it: it is not a third-party bolt-on that needs to be reconciled with the framework's roadmap, it is the framework's opinionated answer to queue management. It installs as a service provider, ships a config file (config/horizon.php) that becomes the source of truth for worker topology, and replaces the bare php artisan queue:work process with a supervised php artisan horizon master process. For a TPM, that means the "architecture decision" here is unusually cheap — there is no adapter layer to design, no custom dashboard to build, and no proprietary schema. The trade-off is that Horizon is not additive: it asserts a specific runtime shape (long-lived PHP process under a process supervisor, Redis as the queue backend, configuration committed to source control). Adopting Horizon is therefore less a library decision and more a queue-operations standardization decision.
The core capabilities that matter for scoping are: code-driven supervisor/queue definitions per environment, two autoscaling strategies (simple and auto/size), job and queue metrics with configurable retention windows, tag-based job filtering, wait-time and runtime monitoring with threshold alerting hooks, and a read-mostly dashboard with a Gate-based authorization hook. Every one of those is a capability a team would otherwise build or buy, so the opportunity is real even at a modest opportunity score — the score likely reflects that the addressable audience is "Laravel teams on Redis" rather than a broader market.
Integration feasibility. High, and bounded. The install path is a single Composer require plus asset publication; auto-discovery handles registration. The genuinely non-trivial work is operational, not code: provisioning a process supervisor, deciding Redis topology, wiring deployment hooks to horizon:terminate so workers don't run stale code, and placing the dashboard behind the authorization gate in every non-local environment. None of these are research problems, but each is a checklist item that, if skipped, produces a production incident rather than a broken test.
The hard constraint is Redis-only. Horizon does not manage database, sqs, or beanstalkd queues. If the existing estate runs SQS — a very common Laravel-on-AWS pattern — Horizon is not an incremental adoption, it is a queue-backend migration with all the durability, IAM, and local-development-parity consequences that implies. This is the single question that determines whether the assessment is "two days" or "two quarters."
Technical risk.
horizon:listen (5.45.1), RedisQueue::later() delay handling regressions across 5.48.2 and 5.48.3, horizon:clear-metrics failing on phpredis 6.1+ (5.48.2), and null/non-array Redis HMGET handling during startup. Most are phpredis-vs-predis or Laravel-minor-version interactions. Treat the PHP Redis client choice and the Laravel minor version as pinned, tested artifacts rather than "whatever Composer resolves."SCAN prefix behavior under phpredis. Teams on clustered Redis should treat Horizon as recently hardened rather than long-proven, and should pilot before standardizing.horizon:reload/terminate deployment contract must be owned by someone.Key questions to resolve before approval.
horizon:terminate and wait for graceful drain?Stack fit. Horizon fits cleanly where the stack is Laravel + Redis + a Linux process supervisor. The changelog confirms support through Laravel 13 and PHP 8.5 compatibility work, so it tracks the framework's release train rather than lagging it. It does not fit serverless or container-per-request platforms where you cannot run a durable supervisor process — Vapor, Lambda, and some PaaS runtimes manage queues externally and would sideline Horizon's core value. Confirm the deployment substrate before scoping anything else.
Migration path. Three credible paths, in ascending order of effort:
config/horizon.php per environment, provision supervisor, add Gate, add deploy hook. Days, not weeks.Compatibility considerations. Pin Laravel minor, PHP minor, and the Redis client; test the combination in CI. Note that horizon:publish is deprecated in favor of the install flow — build the runbook against the current command surface, not older blog posts. If Redis Cluster is in scope, gate activation on the 5.46.0+ line and validate SCAN-based metric clearing explicitly. If a CSP is enforced, plan the nonce wiring up front rather than discovering it in a security review.
Sequencing. (a) Confirm driver and substrate fit. (b) Local install and config authoring on a scratch app. (c) Staging deployment with supervisor, Gate, and deploy hook exercised end-to-end, including a deliberate bad deploy to prove graceful termination. (d) Production pilot on one low-risk queue with a hybrid config. (e) Observe metrics and tune retention and autoscaling thresholds against real traffic for a full business cycle. (f) Roll remaining queues, then decommission the legacy worker topology. (g) Only then standardize across the application portfolio.
Governance. Horizon's config lives in source control by design, which means worker topology changes go through code review — a genuine operational win, and a change-management process worth naming explicitly so it isn't bypassed by hand-edited servers.
Maintenance. The release cadence is fast and mostly patch-level: dependency bumps, PHP/Laravel compatibility shims, and targeted correctness fixes. That is healthy for security posture (the project runs Dependabot auto-merge, a cooldown window, and least-privilege CI workflows) but it does mean a non-trivial upgrade cadence. Budget a recurring monthly slot for version review and a quarterly slot for a staging validation pass. Because releases frequently touch Redis client interaction, an upgrade that looks like a dependency bump can change queue semantics — read the changelog, don't just bump.
Support. MIT licensed, first-party, no commercial SLA. Support is community and maintainer-driven, which for a package this central is usually adequate but is not a contractual guarantee. A TPM should record that queue operations depend on a volunteer-maintained artifact, and that the realistic mitigation is version discipline and a documented manual fallback (queue:work plus external monitoring) rather than vendor escalation. The "dependents: 0" datapoint is almost certainly a registry artifact — this is the de facto standard for Laravel queue management — but it should not be cited as evidence of adoption in a business case; cite internal usage instead.
Scaling. Horizon's autoscaling (auto/size strategies) is genuinely useful: it adjusts worker counts to queue depth rather than forcing static over-provisioning, which translates directly into infrastructure cost. Scaling considerations to plan for: per-worker memory ceiling times max process count must fit the host; Redis becomes both the queue and the metrics store, so memory growth has two sources; autoscaling reacts to backlog, not to downstream dependency saturation, so a slow external API will inflate worker counts rather than relieve pressure. Set maxProcesses deliberately and pair autoscaling with circuit breakers or timeouts upstream.
Failure modes and mitigations.
memory limits, scheduled restarts, and memory alerting.horizon:clear-metrics against the actual Redis client after any client upgrade.Ramp-up. Low for anyone already fluent in Laravel. The config file is declarative and readable, the dashboard is self-explanatory, and the mental model (connections → queues → supervisors → processes) maps onto concepts the team already holds. Realistic estimate: half a day for a Laravel developer to be productive, one to two days for the team to be confident operating it, and the genuine learning curve is on the operations side — process supervision, graceful drain, Redis sizing — not on the package. The one skill gap worth naming is that Horizon makes queue health visible without making it understood; someone must own interpreting wait-time and throughput metrics and turning them into alert thresholds. Assign that owner at adoption, not after the first incident.
How can I help you explore Laravel packages today?