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

Inertia Statamic Laravel Package

mattbromley/inertia-statamic

Bridges Inertia.js and Statamic by serving Statamic content through Inertia responses, so you can build Laravel-driven, JavaScript-rendered front ends on top of Statamic entries without hand-wiring the root view and routing yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small fork (4 stars, no dependents) of Adam Campbell's Statamic↔Inertia adapter, so treat it as a reference implementation you may need to patch rather than a drop-in framework. Read the fork's README and diff it against the upstream before relying on it — the value of the fork is usually a version bump (Statamic 4/5, Laravel 10/11) rather than new features.

Minimal setup:

  1. Install and pin. Because the package has no dependents and a single maintainer, require an exact version and commit your composer.lock:
    composer require mattbromley/inertia-statamic --prefer-dist
    
  2. Install the Inertia client on the JS side (the adapter only handles the server half):
    npm i @inertiajs/vue3   # or @inertiajs/react / @inertiajs/svelte
    php artisan inertia:middleware   # creates App\Http\Middleware\HandleInertiaRequests
    
    Register HandleInertiaRequests in the web middleware group in bootstrap/app.php (Laravel 11) or app/Http/Kernel.php.
  3. Publish the adapter's config and read it before doing anything else — it typically controls the root Blade view, the page-component path convention, and which Statamic data is auto-shared:
    php artisan vendor:publish --provider="MattBromley\InertiaStatamic\ServiceProvider"
    
  4. Root Blade view must contain @inertia and @vite(['resources/js/app.js']); the adapter either ships one or expects you to point the config at resources/views/app.blade.php.
  5. First use case: render a Statamic collection entry as an Inertia page. Hit a route like /blog/{slug}, resolve the entry through the Entry facade, pass the augmented data as props, and render Blog/Show on the front end. That single flow exercises routing, augmentation, prop serialization, and client-side navigation — if it works, the integration is sound.

Where to look first in the source: the service provider (to see what it registers — a route macro, a middleware, a driver), then the class that actually builds the Inertia response. That class is the seam you'll extend.

Implementation Patterns

Route → Inertia response. The adapter's job is to let you do this without fighting Statamic's front-end router:

Route::get('/blog/{slug}', function (string $slug) {
    $entry = Entry::query()->where('collection', 'blog')->where('slug', $slug)->firstOrFail();

    return Inertia::render('Blog/Show', [
        'entry' => $entry->toAugmentedArray(),
        'related' => Entry::query()->where('collection', 'blog')->limit(3)->get()->toAugmentedArray(),
    ]);
});

Prefer toAugmentedArray() / augmentedValue() over passing the entry model directly. Raw Entry objects carry the full YAML/JSON content stack and won't serialize predictably; augmented values go through Bard/Markdown/asset transformations and match what Antlers would render.

Define routes before the Statamic catch-all. Statamic registers a fallback route for its URL-driven front end. Inertia routes must be registered above it (Route::statamic(...) and the fallback both live late in the route file). If your Inertia route returns an Antlers view instead of a JSON/X-Inertia response, route ordering is almost always the cause.

Shared data via HandleInertiaRequests. Use the standard Inertia share() method for nav, globals, and site settings rather than repeating them per page:

public function share(Request $request): array
{
    return array_merge(parent::share($request), [
        'nav' => fn () => Nav::tree('main')->toAugmentedArray(),
        'globals' => fn () => GlobalSet::findByHandle('site')->toAugmentedArray(),
        'flash' => fn () => ['success' => session('success')],
    ]);
}

Wrap in closures so partial reloads don't re-query on every visit.

Partial reloads for listing pages. Statamic entry queries are cheap per-request but the full page payload isn't. On filter/pagination changes, do:

router.get(`/blog?page=${page}`, {}, { only: ['entries', 'meta'], preserveState: true, preserveScroll: true })

Persistent layouts. Use Inertia's persistent-layout pattern for the site chrome so navigation doesn't remount headers/nav — this is the main perceived-performance win over Antlers.

Forms. Statamic's Form addon is server-rendered; bridge it with a normal Laravel controller that calls Statamic\Facades\Form::find('contact')->makeSubmission(), returns validation errors as a 422, and let useForm() handle the rest. Don't try to reuse Antlers form tags inside Inertia pages.

Static site / cache interplay. If you enable Statamic's static caching, Inertia's JSON responses (X-Inertia: true) get cached incorrectly. Either scope the cache to non-Inertia requests or disable static caching for Inertia routes.

Gotchas and Tips

  • It's a fork with a single maintainer and no dependents. Watch the upstream repo (adamcampbell's adapter) and the official Inertia docs; when a version conflict arises you'll likely be the one fixing it. Keep a local patch or a vcs repository entry in composer.json so you can rebase.
  • Route caching breaks closures. php artisan route:cache refuses closure routes. Convert every Inertia route to an invokable controller before deploying to a cached production environment.
  • The web middleware group must run this adapter's middleware after session/CSRF. A misplaced registration produces 419s on router.post or missing shared props on hard reloads but not on client-side visits — a signature mismatch worth remembering.
  • Augmentation is lazy. Calling $entry->toAugmentedArray() inside a shared-prop closure is fine; calling it at controller top-level for a large listing eagerly resolves assets and can be slow. Use ->select() and paginate at the query level.
  • Vite::useHotFile / dev server mismatch shows up as a blank page with no console error — verify the resources/js/app.js entry exists and that @vite points at the same build the Inertia resolvePageComponent glob scans.
  • 409 "Page Expired" after deploy is Inertia asset versioning, not auth. Clear inertia_asset_version (or call Inertia::version(fn () => md5_file(public_path('build/manifest.json')))) as part of your deploy.
  • Debugging: install the Inertia devtools extension and log the response class. Inertia::render(...)->toResponse($request) returns a JsonResponse for X-Inertia requests and a full HTML response otherwise — inspect response()->getStatusCode() and the X-Inertia header to see which branch ran. dd() inside a shared prop closure won't render; log instead.
  • Testing: assert props with Inertia\Testing\AssertableInertia, not assertSee, since content lives in JSON:
    $this->get('/blog/hello')->assertInertia(fn ($page) =>
        $page->component('Blog/Show')->has('entry.title')->where('entry.slug', 'hello'));
    
  • Extension points: the config file (root view, component path), the response-building class (override or bind a subclass in a service provider), and HandleInertiaRequests::share() are where 90% of customization lands. If the adapter's default prop mapping doesn't fit your content model, subclass it rather than editing vendor/.
  • Control Panel is untouched. This adapter is front-end only; don't expect it to affect CP rendering or addons.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core