oza/laravel-database-jsonable
A Laravel package that adds JSON column support to Eloquent models, making it easy to store, retrieve, and cast structured JSON data in your database without custom accessors or mutators.
Architecture fit. oza/laravel-database-jsonable is a persistence-layer convenience: it lets Eloquent models declare JSON-backed attributes and handles fill/retrieve translation between PHP arrays/objects and a database column. That makes it a leaf dependency — it does not touch the request lifecycle, queue workers, or service container bootstrapping, and it introduces no runtime infrastructure (no broker, no cache, no external service). Architecturally it slots cleanly into a domain/infrastructure layer alongside existing casts.
The problem is that it competes with the framework. Laravel has shipped native JSON casting ('meta' => 'array', 'json', AsArrayObject, AsCollection) since 5.x, plus first-class custom casts since 7.x. Any TPM evaluating this should treat the package's value proposition as conditional: it is only justified if it provides something native casts do not — likely dot-notation access to nested keys, per-key defaults, or support for genuinely old Laravel/PHP versions. That must be verified against source before it is treated as a requirement.
Integration feasibility. Mechanically simple: composer require, add the package's trait/attribute declaration array to target models, ensure columns are json (MySQL 5.7+/8, Postgres jsonb) or text on legacy schemas. Realistic effort for a pilot is 2–5 engineer-days including tests; a full rollout across a mature model layer is 2–4 weeks. Feasibility is gated almost entirely on version compatibility — a package at this adoption level frequently lags current Laravel majors, and composer require on Laravel 10/11 may fail or resolve to an unmaintained branch.
Technical risk.
$fillable), toArray()/API serialization, dirty tracking, and model events can behave unexpectedly with custom accessor/mutator layers — a classic source of production surprises.Key questions.
$casts, AsArrayObject, and custom casts do not?json columns only, or does it encourage text columns that forfeit DB-side validation and indexing?Stack fit. Adopt only under one of two conditions: (a) the codebase is on an older Laravel major where native casting is weaker, or (b) the package's nested-access ergonomics measurably reduce boilerplate on models with many JSON attributes. If the target stack is Laravel 9+, the default recommendation is to implement the same behavior with native casts and a small internal base model or trait — roughly one day of work, fully owned, zero dependency risk.
Migration path. Do not retrofit existing models en masse. Sequence:
json column, not text, so the database enforces validity.Compatibility. Run composer why-not oza/laravel-database-jsonable against the pinned framework version. Confirm the DB driver in use and whether JSON path queries are required — if reporting or filtering on nested keys is on the roadmap, this package does nothing for you and native jsonb/generated columns should be the plan. Verify behavior under the ORM's serialization path so JSON attributes do not leak unintentionally into public API payloads.
Sequencing. Audit source and version constraints → spike on one model → contract tests → feature-flag or limit to new code paths → decide keep / fork / replace with native casts → document the JSON shape convention as an ADR.
Maintenance. Day-to-day maintenance is near zero — casting logic is stable. The real cost is ownership: with a bus factor of one and no dependents, assume you may need to fork or vendor the source into the repo. Budget a half-day per Laravel major upgrade to validate it, plus a fallback plan to native casts.
Support. Community-only, no SLA, no vendor. An internal owner must be named before adoption; if no one volunteers, that is the decision.
Scaling. Runtime overhead is negligible — casting happens at hydration and is O(payload). The scaling risk is structural, not computational: JSON columns grow unbounded, are not indexed without generated columns or expression indexes, and defeat SELECT-level projection. Establish a payload size ceiling and forbid JSON columns in hot query paths.
Failure modes.
null or empty-array returns after a framework upgrade changes accessor resolution order.Ramp-up. Low. A mid-level Laravel engineer is productive in hours because the concept mirrors framework-native casting. The learning cost sits in the team convention: which attributes are JSONable, what the allowed shape is, and when to promote a key to a real column. Document that before the second model adopts it.
Recommendation. Do not add this as a production dependency without an audit. The capability is largely reproducible with native Eloquent casts at equal or lower total cost of ownership; the package is defensible only as a reference implementation or a short-term bridge on legacy stacks, and should carry an explicit exit criterion.
How can I help you explore Laravel packages today?