Abdulkader Safi

Filament v3 to v5 was the toll for touching Atelier at all

This site ran Filament v3.3.54 and Livewire v3 with Volt. Atelier needs Filament v5, and Livewire v4 would not install next to Filament v4, so two version jumps landed in one commit. Sixteen admin resources had to survive it without a single behaviour change.

3 min read

Share
A Filament admin resource list rendering correctly after the version 5 upgrade.

Before I could put my own plugin on my own site, I had to get off Filament v3.

This portfolio has run on Filament since before Atelier existed, and it had drifted two major versions behind: v3.3.54, Livewire v3.8.2, Volt components for the two interactive forms on the public side. Atelier needs Filament v5. There was no shortcut around the upgrade, only through it.

The plan that didn't survive contact

The plan was two steps: Filament v3 to v4, confirm nothing broke, then v4 to v5 with Livewire v3 to v4 alongside it, since Filament v5 requires Livewire v4.

Step one worked. Step two didn't start the way I wrote it. composer require livewire/livewire:^4.0 while still on Filament v4 failed outright: Filament v4 pins to Livewire v3. Livewire v4 and Filament v5 arrived together on purpose, and nothing lets you have one without the other.

So the two steps became one. Filament v4 to v5 and Livewire v3 to v4, in the same commit, with no intermediate state to test against. Sixteen admin resources, all of them, had to come out the other side working or the deploy doesn't happen.

What Livewire v4 actually changed

Volt is gone in v4. Both Volt components on the public side, the service contact form and the resource subscribe form, became plain Livewire classes: a mount(), a couple of public properties, a submit() method, a Blade view. Functionally identical, no template difference a visitor would notice.

The part that broke quietly: Livewire v4 ships RequireLivewireHeaders middleware. A hardening test that fired a raw POST at a Livewire update endpoint, to confirm it rejected malformed requests, started failing. Not because the hardening broke, but because the test itself no longer looked like a genuine Livewire request. It needed an X-Livewire header and postJson() instead of a plain post(). The middleware was doing exactly what it should. The test just predated it.

The package that didn't make it

bezhansalleh/filament-google-analytics has no release for Filament v4 or v5. I checked the repo, checked the issues, no branch in progress. It came out. Google Analytics itself didn't go anywhere, it just moved from a Filament dashboard widget to where it already lived on the public site: script tags in the layout head. One less admin panel dependency, same analytics.

Two migrations that assumed too much

A settings table migration failed on a fresh install because it assumed the table didn't already exist, which was true the first time this app was migrated and false on every CI run since. Guarded with Schema::hasTable(), and it stopped mattering how many times the suite ran.

rmsramos/activitylog changed its namespace between the version this app was pinned to and v3. One use statement, caught by the test suite immediately, not by staring at a diff.

Where it stands

Filament v5.7.6, Livewire v4.4.2, zero Volt components, zero regressions across sixteen admin resources and the public site both. This is the boring part of the story, the part where nothing visible changed. Atelier needed a v5 host to land on, and now this site is one.

Last updated 28 Aug 2026 · filed under Laravel, filamentphp, plugin, tools, livewire

Every entry on this project

28 build notes, in order

Including the ones where nothing worked. You are on part 14.

Read the series →

FAQ

Frequently asked questions

Why did upgrading Filament v4 to v5 also force a Livewire upgrade in the same step?

Because Filament v5 requires Livewire v4, and Livewire v4 will not install alongside Filament v4: composer refuses the combination outright. A two-step upgrade plan, Filament first, Livewire second, only works when the intermediate state is installable, and here it wasn't, so both version jumps had to land in one commit with no tested midpoint in between.

What breaks when Volt components are converted to plain Livewire classes?

Nothing visible to a user, done correctly. Volt's single-file syntax, PHP and Blade in one file, becomes a full component: a class with mount(), public properties, and action methods, plus a separate Blade view. The public-facing behaviour is unchanged. What changes is where the logic lives on disk.

Why did a Livewire v4 upgrade break an existing test that had nothing to do with the feature it tested?

Livewire v4 introduced RequireLivewireHeaders middleware, which rejects requests to Livewire's update endpoint that don't look like they came from a real Livewire component, specifically a missing X-Livewire header. A test written against Livewire v3 that posted directly to that endpoint to check hardening behaviour stopped resembling a genuine Livewire request under v4's stricter check, so it needed the header and postJson() instead of post(). The hardening it tested hadn't changed. The shape of a valid request had.

Written by

Abdulkader Safi

Software Engineer

Lead engineer at DSRPT, from Lebanon and based in Kuwait. I write about the tools and bugs from real client work, with the numbers I measured.

About me → GitHub LinkedIn

Need this kind of work done on your project?

Start a project →

Keep reading

More from Filament Atelier

All 28 entries →
  • A version number changing from 0.5.0 to 1.0.0 beside a list of deferred items.
    Filament Atelier

    · part 28 of 28

    Tagging 1.0.0 with four features missing, on purpose

    The gate list had thirteen items. Six went in, seven did not, and the tag went out anyway. What the number promises is that the API stops moving, not that the feature list is finished, and conflating those two is how packages sit at 0.x for three years.

  • The same block of JavaScript appearing in three different Blade layout files.
    Filament Atelier

    · part 26 of 28

    A script in three layouts is a contract nobody signed

    The editor's preview needed a few lines of JavaScript in the page it renders. I put them in the shipped layout, then copied them into two more. Anyone writing their own layout had to copy them too, and missing them broke half the editor with no error at all.