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

Nova Json Schema Field Laravel Package

nsavinov/nova-json-schema-field

A Laravel Nova field that renders and validates JSON input against a JSON Schema, giving you a clean editing experience for structured JSON columns in your Nova resources. Includes schema-driven validation and a friendly form interface.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify compatibility first. This package's last release was September 2018, which predates Nova 2 and was built against Nova 1.x (Vue 2, the old asset pipeline). Before wiring it into a resource, confirm it actually loads in your Nova version:

composer require nsavinov/nova-json-schema-field

Then open a Nova resource form and check the browser console/network for the field's compiled JS. If nothing renders, you are almost certainly on a Nova version the package does not support and will need to fork the field component (see Gotchas).

Where to look first. Read, in this order:

  1. The PHP field class in src/ — it defines the schema() (and any options) methods and the Vue component it points at.
  2. resources/js/components/FormField.vue — this is where the JSON Editor instance is created and where the schema prop is consumed.
  3. The bundled/published assets — if the field renders blank or unstyled, the JS/CSS was not published or compiled.

Publish assets if the README's provider/tag applies to your version:

php artisan vendor:publish --provider="Nsavinov\NovaJsonSchemaField\FieldServiceProvider"

First use case — replace a raw JSON textarea. The ideal candidate is a json/text column holding a settings blob, where you want a schema-driven form instead of hand-editing JSON.

use Nsavinov\NovaJsonSchemaField\JsonSchema; // confirm exact class in your installed version

public function fields(Request $request)
{
    return [
        JsonSchema::make('Settings')
            ->schema([
                'type' => 'object',
                'properties' => [
                    'enabled'  => ['type' => 'boolean', 'title' => 'Enabled'],
                    'endpoint' => ['type' => 'string',  'title' => 'Endpoint', 'format' => 'uri'],
                    'retries'  => ['type' => 'integer', 'title' => 'Retries', 'minimum' => 0, 'maximum' => 10],
                ],
            ])
            ->rules(['nullable', 'array']),
    ];
}

And on the model:

protected $casts = ['settings' => 'array'];

If a schema-driven form renders and saves cleanly on one resource, you have validated the whole stack (assets, schema prop, model cast). Do that before rolling it out to more resources.

Implementation Patterns

Keep schemas out of the resource. Inline schema arrays grow into hundreds of lines and get duplicated across create/update/detail. Hoist them into a config file, a dedicated schema class, or a static method on the model:

// app/Support/Schemas/IntegrationSchema.php
class IntegrationSchema
{
    public static function definition(): array
    {
        return [
            'type' => 'object',
            'properties' => [/* ... */],
        ];
    }
}

// in the resource
JsonSchema::make('Settings')->schema(IntegrationSchema::definition())

Dynamic schemas per record. Because Nova evaluates fields() per request, you can branch on $this->resource to return different schemas for different model types (e.g., a connector_type discriminator). Cache the resulting array — building large schemas on every list request is wasteful.

Read-only in index/detail, editable in forms. The full editor is heavy. Prefer:

JsonSchema::make('Settings')
    ->schema($schema)
    ->hideFromIndex()          // or ->onlyOnForms()
    ->displayUsing(fn ($value) => json_encode($value, JSON_PRETTY_PRINT));

For index columns, a compact Text field showing a summary is usually better than the full editor.

Close the validation gap. The bundled JSON Editor validates client-side, but Laravel never sees those results. Add server-side rules:

->rules(['nullable', 'array'])

For real schema validation, validate in a FormRequest or fillUsing/saving hook using a PHP JSON-schema validator (justinrainbow/json-schema or opis/json-schema) against the same schema array. This is the single most important integration step — otherwise invalid data gets persisted and the editor later refuses to render it.

Normalize the stored value. JSON Editor sometimes emits null, {}, or [] for an "empty" form depending on schema type. Normalize on save via a model mutator or ->fillUsing() so downstream code doesn't have to handle three empty representations.

Pair it with defaults and seeding. ->default([]) combined with a schema that has "default" values per property gives a sensible blank form. For backfilling existing rows, write a one-off command that merges defaults into stored JSON.

Treat the schema as the single source of truth. If the same structure is used in API validation, config resolution, or a front-end consumer, generate those from the schema array rather than hand-maintaining parallel definitions.

Gotchas and Tips

Version compatibility is the headline risk. A 2018 field on modern Nova (3/4, Vue 3) will usually fail to mount. Check the component builds and renders before writing schema code. If it doesn't, plan to fork FormField.vue, port it to Vue 3, and re-point public $component — that is often less work than it sounds and is the realistic path for most teams today.

Blank field = asset or schema problem, not a Nova problem. Debug in this order: (1) is the compiled JS loaded? (2) does the schema prop appear in Vue devtools on the component? (3) does the JSON Editor instance throw on init? Invalid schema shapes (e.g., missing type, malformed properties) fail silently and leave an empty div.

Validate the schema itself. Run your schema through a JSON Schema meta-validator in a test. A typo in properties produces a form that renders partially or not at all, with no server-side error to trace.

$casts mismatches bite. If the column is json but the model casts to string (or not at all), the editor receives a JSON-encoded string and renders nothing useful. Confirm the cast is array/json and that the database column type matches.

Server-side validation is not automatic. Repeated because it matters: JSON Editor's required and format checks are advisory only. Anything that writes to the column outside this field (imports, APIs, seeders) also bypasses them.

Old bundled json-editor. The vendored editor version is from the same era and lacks newer keywords (if/then, $ref resolution quirks, some format validators). If you need modern schema features, either upgrade the bundled library in a fork or accept the constraint.

Index performance. The editor mounts on every row if you leave it on the index. With 50+ rows this visibly hangs the list view. Always hideFromIndex() or use a lightweight display field.

No community safety net. With 26 stars, zero dependents, and a 2018 release, there will be no upstream fixes. Budget for ownership: pin the fork internally, document the Vue component changes, and add a smoke test that opens the form in a browser (Dusk or similar) so a Nova upgrade doesn't silently break the field.

Extension points if you fork. public $component on the field class, the schema prop passed to the component, and a meta() method for passing editor options are the three places to customize. Subclassing the field and overriding meta() is the least invasive way to pass configuration without touching the Vue component.

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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums