Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Roadrunner Laravel Package

spiral/roadrunner

RoadRunner is a high-performance PHP application server and process manager written in Go. It offers HTTP/2/3, gRPC, fCGI, queues, KV storage, and OpenTelemetry via plugins, serving as a powerful alternative to Nginx+FPM.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Unchanged: RoadRunner is not a Laravel package — it is a Go application server plus a thin PHP SDK. The realistic Laravel path remains Laravel Octane's roadrunner driver. Direct SDK use only makes sense if we want the plugin surface (queues, KV, gRPC, Temporal, locks, Prometheus/OTEL, Centrifugo), not for HTTP alone.
  • The value proposition versus Nginx + PHP-FPM is unchanged: bootstrapping amortization per worker plus a self-contained server that absorbs a chunk of Nginx config (static, gzip/zstd, headers, sendfile, TLS, rate limiting, 103 Early Hints).
  • Architectural consequence is unchanged and still the dominant risk: a move from request-scoped to long-lived worker model is an application-code contract change, not an infrastructure swap.
  • From v3.0.0 and still architecturally material: the Go side is an explicitly multi-repository, versioned contract — github.com/roadrunner-server/roadrunner/v3, plugins on v6 Go contracts, api / api-go/v6 / api-plugins/v6 split out, goridge/v4, pool/v2. This widens the version matrix we must pin (binary major, SDK major, Octane major, Go plugin generation).
  • New in v3.0.1 and architecturally neutral: this is a pure patch — no config schema change, no plugin API change, no middleware or protocol behavior change beyond stricter certificate validation. It does not add migration work. Its significance is strategic, not architectural: it confirms v3 is the actively maintained line and that the project ships security patches on it.
  • "We don't build the Go binary" is no longer fully true. TCP requires a custom build; anything needing it, or any custom plugin, puts us in the Go toolchain. Our default posture (copy /usr/bin/rr from the published image) is intact for HTTP, but the premise needs a caveat in the ADR — and the caveat now has a second dimension: a self-built binary is also a self-patched binary, and we inherit responsibility for Go toolchain CVEs.
  • RoadRunner still competes with FrankenPHP and Swoole. Nothing in v3.0.x changes that comparison on governance; FrankenPHP remains the lower-ceremony option if we only need HTTP.

Integration feasibility

  • Still high for HTTP: php artisan octane:install --server=roadrunner, .rr.yaml, multi-stage Docker build copying /usr/bin/rr from a pinned image tag. Prefer pinning by digest; the calendar-tag scheme is replaced by semver-style v3.x, so our Renovate rule must change from 2025.x patterns to v3 majors.
  • Gating unknown: Octane's supported RoadRunner range. Octane historically pins to specific RR majors and has lagged server majors. Before planning a v3 pilot we must confirm (a) Octane's roadrunner driver supports RR v3 wire/config, (b) the spiral/roadrunner-worker / -http / -cli SDK v3 packages are released and Octane constrains to them, (c) Symfony Runtime has v3 support. If any of these is not yet true, the pilot pins to the latest v2025.x and v3 becomes a scheduled follow-on — do not start a new deployment on a major we know we will migrate off within twelve months.
  • New decision input for that gate: if the pilot lands on v2025.x, we must confirm whether a v2025.x build exists that carries the Go 1.27.3 fix. If it does not, "stay on the older major for a year" quietly converts into "run a known CVE for a year," and that changes the gate from a convenience question to a security-driven one. Resolve this before the pilot pin is chosen, not after.
  • The EOF-on-worker-start failure mode is unchanged: missing sockets extension, missing SDK package, or bad server.command. Bake the extension into the image and keep the CI boot smoke test.
  • Config-migration work carried in from v3.0.0 (all must be in the migration doc, not discovered at deploy):
    • http.middleware now evaluates left to right; v5 lists must be reversed to preserve behavior. This is silent — no error, just different ordering.
    • AMQP: config.version removed; static pipelines require config.connection plus nested exchange/queue.
    • MessagePack removed from Goridge RPC; JSON/protobuf/Gob/raw remain.
    • envfile is now non-experimental, and a configured file must exist at startup or the server fails to boot.
    • HTTP/1.1 Upgrade: h2c no longer supported; cleartext HTTP/2 requires prior knowledge.
    • NATS: stream contents are preserved on pipeline stop unless deletion is enabled — redelivery behavior changes on upgrade.
    • dynamic_allocator.max_workers now counts workers above the base pool; any autoscaling tuning numbers recorded from v2025 are wrong for v3.
  • New operational requirement on the pin: digest pinning alone is now demonstrably insufficient — a fixed digest would have left us on the vulnerable Go 1.27.x build indefinitely. Digest pin plus a named re-pin cadence and an owner is the actual control. Add a CI/scanning check that reports the Go toolchain version embedded in the pinned binary so drift is visible.
  • Scoping caveat still stands and gets sharper: the NSQ driver, named job worker pools, and job outcome metrics are RoadRunner queue features, not Laravel queue drivers. They do not become drop-in Laravel features by existing.

Technical risk

  • State leakage between requests — still the highest-severity risk, still an application-correctness problem, not an infra problem. Requires a package compatibility review and code audit before rollout.
  • Version lockstep — confirmed as a real, recurring cost. v3.0.0 is exactly the breaking major the prior assessment budgeted for: Go module path change, plugin API generation change, middleware order inversion, AMQP schema change, RPC codec removal. v3.0.1 validates the other half of the line item: patch releases on a Go server are effectively mandatory and cannot be deferred to the annual cycle.
  • New: the dual-runtime SBOM/CVE surface is now demonstrated, not theoretical. CVE-2026-111943 (crypto/x509, GO-2026-6809) is a Go-stdlib issue that no Composer audit tool will ever report. Our PHP-side security scanning says nothing about this binary. If it isn't in the Go/image scan path, it's invisible.
  • Assessed exposure of this specific CVE: low-to-moderate, pending one confirmation. It affects certificate chain verification. If TLS terminates at the LB and RR only serves cleartext HTTP behind it, our exposure is limited to any place RR itself validates certificates: RR-native TLS/ACME, mTLS to backends, or a plugin making verified outbound calls. If any service uses RR for TLS termination or ACME, treat it as high and patch immediately.
  • New: strictness change bundled in a security patch. The fix rejects known untrusted intermediate certificates. Stricter chain validation can surface as new TLS handshake failures on chains that previously (incorrectly) validated. A security patch that can change connectivity behavior is exactly the class of change that needs a staging verification step, not a blind re-pin.
  • Middleware order inversion is a security-relevant silent change (from v3.0.0). If proxy_ip_parser and rate_limiter swap relative position, IP-keyed rate limiting can key on attacker-controlled headers. Ordering must be explicit, reviewed, and covered by a test.
  • proxy_ip_parser trusted-header selection (http.trusted_headers) — good hardening, but only if configured. Left permissive or misordered, X-Forwarded-For spoofing bypasses rate limits and pollutes audit logs.
  • Expanded default container (from v3.0.0): NSQ, HTTP rate limiting, Zstd, and the protobuf registry ship by default. Larger attack surface and a bigger config surface to review. gRPC server reflection / Protoreg descriptors should be disabled or firewalled in production unless deliberately needed.
  • Dual rate-limiting ownership. RoadRunner can rate limit (global / IP / header key, 429 + Retry-After) and Laravel can too. We must pick a system of record per concern or accept confusing double-counting and mismatched Retry-After semantics between edge and app.
  • Zstd vs gzip. Zstd is a win on ratio/CPU but CDN and intermediary support is uneven; enabling it without a fallback path changes cache keys and breakage mode.
  • Memory behavior. Sawtooth RSS, OOM kills of in-flight requests; max_jobs / max_worker_memory / exec_ttl.
  • Degraded debugging ergonomics — no per-request Xdebug, stack traces across two runtimes. OTEL must precede cutover.
  • Data-quality flags: the earlier 2026-10-09 anomaly is explained — v3.0.0 is dated 2026-10-08 and supersedes v2025.1.13 (2026-04-17). The v3.0.1 security patch landing shortly after the major is a healthy signal: fast turnaround on a stdlib CVE is what a maintained project looks like. Dependents: 0 remains a package-family-split artifact. The modest opportunity score still argues for a pilot-gated decision, not an org-wide bet.

Key questions

  1. Does Laravel Octane's roadrunner driver support RR v3 today, and which SDK major does it constrain? If no — we pin v2025.x and v3 becomes a scheduled upgrade, not a launch blocker.
  2. New: Is there a v2025.x build carrying Go 1.27.3? If not, does that override the "don't launch on an old major" preference and force the v3 pilot?
  3. New: What is our re-pin SLA for RoadRunner patch releases, and who owns it? A digest pin without a re-pin cadence is a silent CVE liability.
  4. New: Where does RoadRunner itself terminate or verify certificates in our design — LB only, RR-native TLS/ACME, mTLS to backends, or plugin outbound calls? This determines whether a crypto/x509 CVE is a low note or a page.
  5. Do we need anything beyond HTTP (queues, KV, gRPC, Temporal, locks)? If no, this remains an Octane-driver decision and FrankenPHP deserves equal evaluation.
  6. Do we need TCP or custom Go plugins? If yes, we own a Go build pipeline, a Go patch cadence, and the "official image only" premise collapses for that service.
  7. Who owns .rr.yaml and the binary pin, and what is the review standard for middleware ordering and trusted headers?
  8. What is our trusted-proxy model end to end — which hop terminates TLS, which headers are authoritative, and where is proxy_ip_parser configured relative to rate_limiter?
  9. Does RoadRunner's rate limiter replace or complement Laravel's RateLimiter? Which layer owns 429s and Retry-After?
  10. Supported PHP baseline (8.3 vs 8.4) and does the pinned v3 build support it?
  11. Support policy for an MIT/community project with Discord-first support and no vendor SLA — acceptable for tier-1, or is FrankenPHP's foundation-backed governance the safer default at the top tier? Note the counter-signal: v3.0.1 shows the community model responding to a CVE quickly.
  12. Have we audited our top ~20 Composer packages for long-lived-process safety (static state, service-provider singletons)?
  13. HTTP/3 — still out of scope (experimental). Confirm no team has enabled it opportunistically.

Integration Approach

Stack fit

  • Target path unchanged: Laravel → Octane (--server=roadrunner) → RoadRunner Go server → PHP CLI workers. spiral/roadrunner and siblings arrive transitively; app code must not call them directly.
  • Container topology unchanged in shape: multi-stage Dockerfile, COPY --from=ghcr.io/roadrunner-server/roadrunner:<pin> /usr/bin/rr. Pin by digest, with a documented re-pin cadence for patch releases (v3.0.x), separate from the major-tracking rule.
  • .rr.yaml is reviewed like code. Minimum review checklist now includes:
    • server.command, http.address, http.pool.*, http.request_body_limit, http.middlewares in the left-to-right order.
    • Middleware sequence with a written rationale: proxy_ip_parser strictly before rate_limiter; zstd/gzip before static; headers last.
    • http.trusted_headers explicitly enumerated — never default-permissive.
    • rpc.listen bound to localhost/Unix socket only, using the Unix socket mode/owner/group attributes where supported rather than TCP.
    • envfile present and mounted, or omitted entirely. Never declare a path that may not exist.
    • logs.mode: production; gRPC Protoreg reflection off unless required.
  • LB keeps TLS termination and real-client-IP preservation. Note the h2c change: if anything between the LB and RR speaks cleartext HTTP/2, it must use prior knowledge, not Upgrade: h2c.
  • New: a "does RR validate certificates here?" line in the service design template, so the CVE-exposure question has a standing answer rather than being re-litigated per incident.

Migration path

  1. Feasibility gate (days): confirm Octane → RR v3 support and SDK availability. Confirm whether v2025.x has the Go 1.27.3 fix. Decide v3 vs v2025.x for the pilot and record the reason. Everything downstream depends on this answer.
  2. Spike (1 sprint): one low-risk internal service on Octane/RoadRunner in staging. Measure p50/p95, RSS per worker, and RPS against the FPM baseline. Publish the delta — this is the go/no-go gate.
  3. v3 config delta pass: apply the migration doc — reverse middleware list, AMQP schema if used, drop MessagePack from any RPC tooling, verify envfile, re-baseline dynamic_allocator numbers, decide gzip vs zstd with fallback.
  4. Patch baseline: start at v3.0.1 or later, never v3.0.0. Do not carry the pre-fix Go toolchain into the pilot as a known exception.
  5. App-readiness pass: singletons, static state, closures in config, storage/filesystem assumptions, uploads, session driver. Fix findings; add a CI lint rule where feasible.
  6. Observability first: OTEL traces plus Prometheus metrics wired before cutover. Add RR's own job/worker metrics if we adopt queues later.
  7. Canary: 5–10% of traffic behind the existing LB for a full business cycle including a peak. If RR handles any TLS, explicitly validate certificate chains in staging first — the stricter verification in v3.0.1 can surface as new handshake failures.
  8. Full cutover, keeping the FPM image buildable and deployable for one release cycle as the rollback path. Decommission Nginx/FPM after that.

Compatibility

  • The matrix is now four-way: PHP version × RR binary major (v3.0.x) × Octane major × SDK major. Encode all four in CI and fail loudly on drift.
  • PSR-7/PSR-17/PSR-15 surface is standard; Laravel's HTTP layer is unaffected. Risk concentrates in long-lived state, third-party packages, and in middleware ordering and proxy-trust configuration.
  • v3.0.1 has no compatibility surface of its own — it is a drop-in patch on v3.0.0 apart from stricter certificate handling. It requires no config change and no code change.
  • Do not couple the v3 upgrade to any feature adoption (queues, NSQ, gRPC reflection, rate limiting at the edge). Land v3 as a like-for-like upgrade first; adopt new capabilities in separate changes with their own tests.
  • Exclude experimental HTTP/3 from initial scope.

Sequencing

Octane/RR version gate (+ v2025.x CVE-backport check) → binary pin at v3.0.1+ + Docker image → .rr.yaml baseline and v3 middleware-order + trusted-headers review → Octane install + worker bootstrap → pool tuning → re-baseline autoscaling against new dynamic_allocator semantics → OTEL/Prometheus → load test vs FPM baseline → app-readiness fixes → canary → cutover → FPM decommission. CI gains a smoke job that boots rr serve and asserts a 200, a job asserting the compiled .rr.yaml middleware order matches an expected fixture, and a job that reports the embedded Go toolchain version for the pinned digest.

Operational Impact

Maintenance

  • Two runtimes to patch, unchanged: Go binary via base image, PHP SDK via Composer, treated as a linked major pair in Renovate.
  • The annual breaking-major line item is confirmed and larger than the prior estimate. v3 requires config edits in the HTTP middleware, AMQP, NATS, and envfile paths, plus an RPC codec removal. Budget it as a real project per major, not a config diff.
  • New and now concrete: a patch cadence, not just a major cadence. v3.0.1 is a stdlib CVE fix. Expect several of these per year, on the project's schedule rather than ours. Minimum viable control: a monthly re-pin review that reads the RR release feed, plus an image/Go scan in CI so the embedded toolchain version is visible without a human reading release notes. Without this, a "pinned" deployment silently ages into known vulnerabilities — the pin becomes the problem rather than the control.
  • New ongoing obligation: watch api, api-go/v6, and api-plugins/v6 for anyone writing or maintaining custom plugins — three more repos in the dependency graph, each with its own patch obligation.
  • .rr.yaml remains infrastructure config in app repos; it carries security-relevant knobs (trusted headers, proxy protocol, rate limiter, Unix socket permissions, TLS) and therefore needs a named owner and a review checklist, not just a reviewer.

Support

  • MIT, no license risk.
  • Community support model unchanged: Discord, GitHub Discussions, Gurubase. No vendor SLA.
  • Refined read on project health: v3.0.0 shipped a documented migration guide with linked PRs, and v3.0.1 addressed a Go stdlib CVE promptly. That is a project that takes security seriously, and it is a meaningful positive signal. It still does not constitute an SLA on tier-1 services.
  • The pattern that matters: a breaking major with a documented upgrade path and no LTS branch means we are the maintainers of our version between upgrades — including backporting judgement calls. Either accept that, buy commercial support, or choose FrankenPHP's foundation-backed governance for the highest tier.

Scaling

  • Horizontal scaling unchanged: stateless replicas, scale by pod count.
  • Autoscaling must be re-baselined. dynamic_allocator.max_workers now means workers above base pool, and idle-worker removal changed. v2025-era tuning notes are invalid for v3. Treat the new retry-on-acquire behavior as a latency-smoothing feature, not a capacity guarantee.
  • Worker recycling (max_jobs, max_worker_memory, exec_ttl) remains the primary leak containment. Set conservatively, tighten from observed RSS.
  • Never expose RPC externally; prefer the Unix socket mode/owner/group controls over a TCP listener.
  • If we later adopt RR queues: named worker pools per pipeline are genuinely useful (isolate slow jobs from fast ones) and job outcome metrics are a real observability gain — but both are future workstreams requiring bespoke Laravel adapters.

Failure modes

  1. Cross-request state leakage — highest severity, silent, surfaces as wrong-user data or permission bleed in production. Mitigate with audit, singletons ban, and integration tests that hit the same worker twice with different identities.
  2. Middleware order inversion after v3 — silent behavior change; can put rate_limiter ahead of proxy_ip_parser and turn IP limits into header-controlled no-ops. Caught only by an explicit ordering test.
  3. Spoofable client IP — permissive or missing http.trusted_headers lets a client forge the key used for rate limiting and audit logging.
  4. New: stale binary pin carrying a known CVE. No error, no alert, no failing test — the deployment simply stays on a vulnerable Go toolchain because nobody re-pinned. Detected only by scheduled scanning or a manual cadence.
  5. New: stricter certificate validation surfacing as a runtime failure. Upgrading to v3.0.1 can reject chains that previously validated. Presents as intermittent TLS/connection errors on affected integrations; must be exercised in staging, not discovered at cutover.
  6. Worker crash/OOM — RR restarts; in-flight requests drop. Requires LB retries and idempotent writes.
  7. Silent memory growth — sawtooth RSS, contained by recycling, leak still needs fixing.
  8. Startup failure from a missing envfile — hard boot failure if declared but absent; a container/ConfigMap mismatch now takes the service down at boot rather than at first request.
  9. Version drift across binary/SDK/Octane → boot failure at deploy. Caught by the CI boot smoke test.
  10. h2c regression — anything still relying on HTTP/1.1 Upgrade: h2c between LB and RR breaks silently after v3.
  11. Body size / timeout divergence from Nginx defaults — explicit request_body_limit, read_timeout, max_request_size required or uploads and slow endpoints fail in ways FPM never did.
  12. Graceful shutdown — terminationGracePeriodSeconds must exceed longest request duration.
  13. Debugging blind spots — no per-request Xdebug; OTEL must exist before cutover.
  14. Expanded default plugin surface — NSQ, rate limiter, Zstd, protobuf registry on by default; unconfigured/unused plugins are unowned attack surface and should be explicitly disabled in production config.

Ramp-up

  • Team training rises slightly: ~3 days on the long-lived worker model, Octane lifecycle events, pool tuning, plus middleware ordering and proxy-trust semantics — the two v3 traps that produce production incidents rather than errors.
  • One sprint of platform work for the pilot end to end (image, config, observability, load test, runbook), plus per-service app-readiness remediation of unknown size — still the main unknown, still to be time-boxed as discovery.
  • If we adopt v3 at the pilot, add a half-sprint for the config migration and version-matrix CI work; if we start on v2025.x, schedule the v3 upgrade as a distinct ticket with the same budget — and add the CVE-backport verification as a prerequisite.
  • New runbook/process entries: binary re-pin and verification procedure, Go-toolchain version visibility in CI, certificate-chain validation check for any RR-terminated TLS, and a documented path for "security patch released, deploy within N days" that does not require a full change-review cycle.
  • New runbook entries otherwise unchanged: worker pool saturation, RSS trend alerting, RPC health, middleware-order regression check, trusted-header verification, graceful restart, rollback-to-FPM.
  • On-call load increases modestly for the first two releases; plan for it rather than absorbing it silently.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin