hyvor/laravel-json-meta
hyvor/laravel-json-meta adds JSON metadata columns to Eloquent models via a simple trait, with helpers for reading, writing, and querying arbitrary meta fields stored in JSON columns.
hyvor/laravel-json-meta is a small Eloquent add-on: a trait that maps a JSON column to a typed, schema-constrained metadata structure, so models reject unknown or malformed meta keys instead of accepting arbitrary arrays. It targets a real gap — Laravel's native array / AsArrayObject casts are untyped and unvalidated, so metadata drifts over time and every consumer has to defend itself against shape changes.
Architecture fit. Good on paper. It is a pure application-layer concern: one trait on a model, one JSON column, no new infrastructure, no queue, no external service. It slots into an existing Eloquent-centric codebase without touching the request lifecycle or the persistence layer's contract. The "strict" posture is the differentiator versus a plain cast — it moves metadata shape errors from runtime consumers to the write path, which is the correct place to catch them.
Integration feasibility. Trivially low effort. Composer install, use the trait, declare the schema, run a migration to add the column. Realistically a one-to-two day spike, not a sprint. The friction is not technical, it is governance: adding an archived dependency requires an explicit exception in most dependency policies.
Technical risk. This is where the package fails the bar. It is archived as of the last release (May 2024), has 10 stars, and is a vendor-published utility rather than a community-maintained library. Laravel ships a major version roughly annually and drops PHP versions on a similar cadence; an archived package's composer.json constraints will eventually block a framework upgrade and there will be no upstream fix. Star count is a proxy for test coverage and battle-testing, and 10 is effectively zero — you would be the primary integration tester. There is also no security-response channel, so any future CVE in the dependency goes unpatched unless you fork it. The mitigating factor is blast radius: the package governs metadata, not money movement or auth, so a failure is recoverable, and MIT licensing means forking is legally unencumbered.
Key questions for the maintainer or spike:
composer.json constraints for php and illuminate/*, and does it install cleanly on the current Laravel LTS?Model::withoutEvents() / bulk upsert() paths that bypass mutators?Recommendation. Do not adopt as a runtime dependency for new work. Treat it as a design reference. The capability is reproducible in-house with a custom cast plus DTOs in roughly one to two weeks, which buys permanent ownership, no upgrade cliff, and no archived-dependency exception. If the team wants to move fast, fork it, vendor it privately, and assign a named owner — but only if the metadata feature is genuinely on the critical path.
Stack fit. Assumes a conventional Laravel stack — Eloquent models, MySQL 5.7+/8.0, PostgreSQL 9.4+ or SQLite with JSON column support. No conflict with standard service providers, no bootstrapping hooks, no published config that could collide. It composes cleanly with existing casts on the same model (dates, enums) since it occupies one attribute.
Compatibility. The archived status converts a routine framework upgrade into a project. Before any integration, verify the installed version against the Laravel version in the target environment. If the app is already on a newer Laravel than the package's constraint allows, composer resolution will fail and the work stops there — that is the cheapest possible kill signal and should be tested first, before any design work. Pin the exact version and never allow a floating constraint.
Migration path. Three viable routes, in order of preference:
spatie/laravel-data if the team already uses it. No dependency, same semantics, full control over error handling.Sequencing. (1) Composer-resolution spike against the current framework — one hour, decides go/no-go. (2) Parity prototype on a single low-traffic model, comparing the package's behavior to a native cast for the write, read, and malformed-data paths. (3) Decide fork versus build based on that prototype. (4) If forking, internalize before the first production write, not after — retrofitting ownership onto a live dependency is how these become permanent. (5) Roll out to one model, observe for a release cycle, then expand. Do not touch multi-tenant or audit-relevant metadata in the first wave.
Maintenance. Ownership inverts on adoption: you become the maintainer of record. Every Laravel upgrade now includes a manual check of a package that will never publish a compatible release. Dependency-scanning tools (Dependabot, Snyk, Trivy) will flag the archived status and, in regulated environments, will generate a standing exception that someone must renew each audit cycle. That recurring paperwork cost usually exceeds the cost of the native build within a year.
Support. Effectively none. Documentation is a README, there is no issue triage, and community answers are nonexistent at this star count. Internal engineers debugging a schema edge case will be reading source, not docs — budget for that in estimates.
Scaling. JSON column read/write performance is a non-issue at any realistic volume; this is metadata, not telemetry. The scaling concern is queryability: nested JSON keys are not indexed unless you add generated columns or expression indexes, so any feature that filters or aggregates on metadata will table-scan. Keep metadata out of list-view filters and reporting paths. Write amplification is also worth a look if the trait rewrites the whole JSON document on every attribute change on wide models.
Failure modes.
upsert(), raw query builder writes, and seeder paths skip the cast entirely and write unvalidated JSON. Strictness is not enforced at the database layer.Ramp-up. Small for the mechanism, deceptive for the context. Any Laravel developer understands a trait and a cast in an afternoon. The real cost is the tribal knowledge that this dependency is dead — new hires will assume it is maintained, attempt to upgrade it, and lose a day. That has to be written down in the repo, in the same place the fork's ownership is recorded.
Verdict. Low technical risk, high lifecycle risk, negligible switching cost. The package is cheap to try and expensive to keep. Given that the functionality is reproducible natively in under two weeks and that adoption creates a permanent upgrade and audit liability, the right TPM call is to borrow the design and skip the dependency — unless the metadata feature is already committed to a roadmap, in which case fork it, name an owner, and put an exit review on the calendar for the next framework upgrade.
How can I help you explore Laravel packages today?