bgaze/laravel-kvstore
bgaze/laravel-kvstore provides a simple, database-backed key-value store for Laravel applications. Store and retrieve arbitrary values—strings, arrays, objects—through an intuitive API with dot-notation support, caching, and easy integration for app settings, preferences, and small configuration dat...
Architecture fit. The package exposes a key-value store over a single text column, with a third set() argument controlling serialization. That is a conventional Laravel shape — facade/service-provider binding, publishable config and migration, cast vocabulary (array, json, object, collection) deliberately mirroring Eloquent's. Teams already fluent in Eloquent casts will read the API correctly on first contact. The one architectural wrinkle worth flagging is that this cast argument is not Eloquent's $casts: it governs only the write path, and a scalar cast is a no-op rather than a coercion. That divergence is exactly what v2.3.0 is cleaning up, and it is now enforced rather than documented.
Integration feasibility. Low. No schema change, no new dependency, no config surface described. The release inserts a validation guard at the top of set() and adds regression coverage for the pass-through types (strings, numbers, booleans, null, DateTimeInterface, __toString objects, Collection). Adoption is a Composer bump plus an audit of call sites.
Technical risk. The substance of the release is a correctness fix: a non-serializing write to a text column previously failed loudly on insert (Array to string conversion) but failed silently on update, where the driver wrote raw JSON that was then indistinguishable from an intentionally stored JSON string. Failing closed is unambiguously the right call. The residual risk is release hygiene, not code: this is a behavior change shipped as a minor (2.3.0), which is defensible only because the old behavior was documented as a limitation rather than supported — but it means a routine composer update can introduce production exceptions with no major-version signal. Second, the guard prevents new degraded rows; it does nothing about rows already written that way, and the notes offer no audit or backfill tooling.
Key questions.
set() guaranteed to leave no partial state?Stack fit. Any Laravel application using the default database layer. The change actually improves cross-driver consistency: the silent-degradation path depended on the driver choosing to serialize arrays itself, so behavior previously varied by backend. Post-2.3.0 the contract is uniform — serialize explicitly or get an exception.
Migration path. Bump to 2.3.0, then sweep KvStore::set call sites for values that are arrays, plain objects, or enums. Each needs either a serializing cast (array, json, object, collection) or a manual json_encode. The trap to call out explicitly in the upgrade ticket: replacing a missing cast with a scalar cast looks like a fix and is not one — set('features', ['beta' => true], 'integer') still throws. Values already stored through a serializing cast need no action; reads are untouched.
Compatibility. No migration, no config change, no read-path change. Previously stored values remain readable, including the degraded ones — which is the good news and the bad news, since it means the ambiguity persists in existing data.
Sequencing.
set() call sites and classify each by value type.Maintenance. Minimal footprint and a defensive guard rather than a behavioral rewrite. The release notes' claim that the suite now pins every pass-through type is the most operationally valuable line in the changelog — it means the guard cannot narrow silently in a future release without a red build.
Support. The new failure is loud, typed (InvalidArgumentException), and self-diagnosing: it names the type received and the cast that resolves it. That is close to ideal for a library error and should keep ticket volume low. The support burden shifts to whoever reads the exception in a log without context, so alerting on that exception class during the rollout window is worth the five minutes.
Scaling. Negligible. A synchronous type check ahead of a single-column write adds no queries and no allocation of consequence. No impact on read throughput or cache behavior.
Failure modes.
Ramp-up. Low for new users — one paragraph of documentation covers "serializing cast vs. no cast," and the exception teaches the rest. For existing users, the cost is a one-time audit proportional to the number of set() call sites, which is typically small in a key-value store usage pattern.
How can I help you explore Laravel packages today?