roadrunner/kv
RoadRunner KV is a PHP client for RoadRunner's key-value storage plugin, offering a simple API for get, set, delete, and batch operations. Use it with memory, BoltDB, Redis, or Memcached backends for fast caching and persistent data in RoadRunner-powered apps.
What it is. roadrunner/kv is a thin PHP SDK over the RoadRunner KV plugin's RPC protocol. RoadRunner is a Go application server that replaces PHP-FPM; the KV plugin exposes a unified key-value API in front of Redis, Memcached, BoltDB, or in-memory stores, with connection pooling and serialization handled in Go. The package gives PHP workers a client (KV class, KVInterface, DTOs like Item/ItemsList) plus a namespace-scoped API.
Architecture fit — conditional, and the condition is heavy. This package has no standalone value. It is inoperable outside a RoadRunner worker process: it speaks the worker↔server RPC protocol, not Redis/Memcached wire protocols. The realistic Laravel path is Laravel Octane with the RoadRunner driver. If our stack is PHP-FPM, nginx, and predis/phpredis, adopting this package means adopting a new application server, a Go binary in the deploy artifact, and a .rr.yaml config surface — an infrastructure program, not a composer require. If we are already on Octane + RoadRunner, the marginal integration cost drops to hours and the value proposition (pooled connections, lower per-op latency, backend-agnostic API) becomes legible.
Contract mismatch with Laravel. The SDK is a low-level KV client, not a PSR-16 or PSR-6 implementation, and it does not implement Illuminate\Contracts\Cache\Repository. Expect to write an adapter. Critically, verify feature gaps before assuming parity with the Redis driver: atomic increment/decrement, cache tags, atomic locks, TTL semantics on mset, and remember/rememberForever behavior all need explicit confirmation. Laravel's cache contract is richer than "get/set/delete," and a partial adapter that silently degrades will surface as production correctness bugs, not performance bugs.
Access boundary risk. Reads and writes are scoped to RoadRunner worker processes. Schedulers, queue workers not running under RoadRunner, artisan commands, and sidecar services cannot use this SDK. Anything needing KV access outside the RR runtime requires a second, parallel code path to the same backend — which reintroduces the very client library this package was meant to displace.
Technical risk — high, concentrated in three areas.
spiral/roadrunner-kv → roadrunner/kv), which already implies churn for anyone who adopted early.Key questions for the vendor/team.
phpredis and a pooled Go client at current traffic? If sub-millisecond, the benefit is unquantified.Stack fit. Viable only in a Laravel 10/11 + Octane (RoadRunner driver) + PHP 8.1+ environment. Not viable for FPM, not viable for shared hosting, not viable for teams without Go-binary deployment experience.
Prerequisites and sequencing. The order matters; each step is a gate.
.rr.yaml in production for a full release cycle. Do not co-mingle this with the KV decision.roadrunner/kv alongside roadrunner-php/roadrunner (or spiral/roadrunner-worker on older pins), matching versions explicitly and pinning both in composer.json with a caret on the minor.kv section of .rr.yaml — driver, addresses, pool size, timeouts — and treat that file as reviewed infrastructure config, not application config.KVInterface as a singleton, a config/kv.php that mirrors .rr.yaml (two sources of truth is a real hazard; generate one from the other if possible), and a facade.Repository implementation. Publish explicitly which methods are unsupported and make them throw rather than no-op.Migration path. Do not migrate existing cache traffic wholesale. Run the KV path in parallel behind a config flag on one bounded workload, compare hit rates, latency, and error rates against the incumbent for two weeks, then expand or revert. Keep the existing Redis/phpredis client in the dependency tree as the fallback and as the escape hatch for unsupported operations.
Compatibility notes. Enforce a version matrix in CI: PHP version × RoadRunner binary version × SDK version. Add a smoke test that boots RoadRunner and round-trips a key; without it, protocol skew ships silently.
Maintenance. Low code churn, high surface area. The application code is small; the owned infrastructure is not — a Go binary in the build artifact, a .rr.yaml to govern, and a third-party protocol contract to track. With 0 dependents, we are effectively an early adopter absorbing the cost of discovering breakage. Budget for reading RoadRunner release notes on every bump, not just this package's.
Support. Upstream support is community/org-driven with no commercial SLA in evidence. Internal support requires at least one engineer who can debug Go-side plugin behavior and read the RPC layer, not just PHP. That is a single point of failure unless deliberately duplicated.
Scaling. Scales exactly as far as the chosen backend. Redis/Memcached behind a pooled Go client is a reasonable high-throughput design and likely the package's strongest technical argument. BoltDB or in-memory silently caps you at one node — a trap worth documenting in the ADR. Also confirm plugin pool sizing against Octane worker count; undersized pools produce queueing that looks like backend latency.
Failure modes to instrument.
null for unsupported increment will corrupt counters without erroring.Ramp-up. Assume 2–3 engineer-days to first working integration for someone fluent in Octane, and 1–2 weeks to production-grade (adapter hardening, observability, fallback, failure drills). For a team without Octane experience, front-load the RoadRunner learning curve separately — it is the dominant cost, and this package is downstream of it.
Recommendation. Do not adopt as a strategic dependency. The package is a narrow optimization whose payoff is real only inside an existing RoadRunner footprint, and whose adoption cost outside one is an order of magnitude larger than 11 stars and 0 dependents justify. Sanction it as a pilot-only evaluation, gated on (a) Octane + RoadRunner already in production, (b) a verified release cadence after resolving the future-dated release metadata, and (c) an explicit inventory of cache features we are willing to forgo. If any gate fails, use the native phpredis/predis client — it works in every process, needs no new runtime, and has a support ecosystem this package cannot match.
How can I help you explore Laravel packages today?