Search

Filament v3 to v5: Skipping a Version Without Breaking Your Panel

Filament v3 to v5: Skipping a Version Without Breaking Your Panel

Key takeaways

  • You can go from v3 to v5 in a single branch, but not in a single step. Run the v4 upgrade script first, then the v5 script.
  • Almost all the real work is the v3 → v4 jump: unified actions, the new Schema API, Tailwind CSS v4 themes and a handful of changed defaults.
  • Most changed defaults can be reverted globally with configureUsing() in a service provider, which keeps the upgrade diff small.
  • Filament v3 stopped getting bug fixes on 1 August 2026. Security fixes continue until 1 January 2028.

 

Plenty of production panels are still on Filament v3. Maybe v4 arrived mid-project, or the “v4 is a big one” warnings put you off. Now there’s a v5, and the obvious question is whether you can skip straight to it.

Yes, and in 2026 it’s the sensible thing to do. Filament v5 is Filament v4 plus Livewire 4 support, so upgrading to v4 and stopping there saves you almost nothing. This guide shows how to make the jump safely in one branch, with two automated passes and a short list of manual fixes.

Why you can’t do it in one command

Each upgrade script only knows about one version jump:

  • filament/upgrade:^4.0 (run with vendor/bin/filament-v4) contains the Rector rules that rewrite v3 code into v4 code: namespaces, method renames, the new schema API.
  • filament/upgrade:^5.0 (run with vendor/bin/filament-v5) only checks for v4 → v5 issues, which is mostly the Livewire 4 move.

If you require filament/filament:^5.0 directly on a v3 codebase, Composer will install it, but none of your v3 code gets rewritten and the panel won’t boot. So the method is two passes, one branch, one deploy. You never ship v4 to production.

Check your platform first

RequirementFilament v3Filament v5
PHP8.1+8.2+
Laravel10+11.28+ (12 and 13 supported)
Livewire34 (^4.1 on current releases)
Tailwind CSS (custom theme)v3v4
doctrine/dbalRequiredNo longer required by Filament

If you’re on Laravel 10, upgrade Laravel first as a separate, deployed step. Mixing a framework upgrade with a Filament rewrite makes failures hard to diagnose. If you want to end up on Laravel 13, read our Laravel 13 compatibility checklist, which covers the PHP 8.3 minimum.

If your app uses doctrine/dbal for its own reasons (old column-change migrations, for example), add it to composer.json directly. Filament v4 stopped pulling it in.

Pass 1: Filament v3 → v4

Run the v4 upgrade script

git checkout -b upgrade/filament-v5

composer require filament/upgrade:"^4.0" -W --dev
vendor/bin/filament-v4

# Run the commands the script prints, then:
composer require filament/filament:"^4.0" -W --no-update
composer update

If installing the script fails, the v4 upgrade guide points out that it uses Rector 2. That means you need PHPStan 2+ or Larastan 3+. Bump those first.

Commit straight after the script runs. Its diff is large and mechanical, and you want it in a separate commit from your manual fixes.

Decide on the new directory structure

Filament v4 introduced a new default layout for resources, with each resource in its own folder and separate Schemas and Tables classes. You can keep the old structure or migrate:

php artisan filament:upgrade-directory-structure-to-v4 --dry-run
php artisan filament:upgrade-directory-structure-to-v4

The command can’t fix every reference between classes in the same namespace, so run PHPStan afterwards to catch broken imports. If you migrate, you’ll match the generators and the docs from now on, which makes life easier for both people and AI coding agents.

Publish the config and keep v3 file behaviour

php artisan vendor:publish --tag=filament-config

Two settings matter here. The default filesystem disk now follows FILESYSTEM_DISK, not FILAMENT_FILESYSTEM_DISK, and new code generation has different defaults. To keep v3 behaviour:

// config/filament.php
use Filament\Support\Commands\FileGenerators\FileGenerationFlag;

return [
    'default_filesystem_disk' => env('FILAMENT_FILESYSTEM_DISK', 'public'),

    'file_generation' => [
        'flags' => [
            FileGenerationFlag::EMBEDDED_PANEL_RESOURCE_SCHEMAS,
            FileGenerationFlag::EMBEDDED_PANEL_RESOURCE_TABLES,
            // Only if you did NOT run the directory upgrade command:
            FileGenerationFlag::PANEL_RESOURCE_CLASSES_OUTSIDE_DIRECTORIES,
            FileGenerationFlag::PANEL_CLUSTER_CLASSES_OUTSIDE_DIRECTORIES,
        ],
    ],
];

The manual breaking changes, in order of pain

The script handles namespaces and renames. It doesn’t change behaviour you depended on. These are the changes that surprise v3 teams:

  1. File visibility is private on non-local disks. FileUpload, ImageColumn and ImageEntry now default to private visibility on disks like S3, so images load through temporary signed URLs. Public buckets suddenly show broken images, and generating signed URLs can slow tables down.
  2. Table filters are deferred. Users now click “Apply” before filters run.
  3. Grid, Section and Fieldset no longer span the full width by default. Two-column resource forms suddenly put sections side by side.
  4. unique() ignores the current record by default. This is usually what you wanted anyway, but check any code that relied on the old behaviour.
  5. The 'all' pagination option is gone by default. Good for performance, but some users will complain.
  6. Custom themes need Tailwind CSS v4. More on this below.
  7. Tailwind classes in your own views stop working without a custom theme. Filament’s views now use @apply in CSS, so utility classes you “borrowed” from Filament’s compiled stylesheet are no longer included.

You can reverse items 1, 2, 3, 4 and 5 globally, which keeps the upgrade small. Put this in AppServiceProvider::boot() and remove each line later, when you’re ready to adopt the new default:

use Filament\Forms\Components\Field;
use Filament\Forms\Components\FileUpload;
use Filament\Infolists\Components\ImageEntry;
use Filament\Schemas\Components\Fieldset;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Table;

public function boot(): void
{
    // 1. Keep public file visibility on S3-style disks
    FileUpload::configureUsing(fn (FileUpload $c) => $c->visibility('public'));
    ImageColumn::configureUsing(fn (ImageColumn $c) => $c->visibility('public'));
    ImageEntry::configureUsing(fn (ImageEntry $c) => $c->visibility('public'));

    // 2 + 5. Instant filters and the "all" page option
    Table::configureUsing(fn (Table $table) => $table
        ->deferFilters(false)
        ->paginationPageOptions([5, 10, 25, 50, 'all']));

    // 3. Full-width layout components
    Fieldset::configureUsing(fn (Fieldset $c) => $c->columnSpanFull());
    Grid::configureUsing(fn (Grid $c) => $c->columnSpanFull());
    Section::configureUsing(fn (Section $c) => $c->columnSpanFull());

    // 4. v3-style unique() validation
    Field::configureUsing(fn (Field $f) => $f->uniqueValidationIgnoresRecordByDefault(false));
}

Other changes to review, depending on what you use:

  • columnSpan(2) now targets lg and up, the same as columns(). Code that used ['lg' => 2] can be simplified.
  • Enum fields always return enum instances. Select, Radio and CheckboxList bound to an enum no longer sometimes return the raw value.
  • URL query parameters were renamed: tableFilters → filters, tableSearch → search, activeRelationManager → relation, and so on. Bookmarked filtered URLs and custom getUrl() calls break.
  • Tenancy now scopes every query in the panel automatically and associates new records with the tenant. Remove manual scoping you added in v3, or you may end up filtering twice.
  • Overriding canCreate() / canEdit() on resources. These aren’t always called any more. Move the logic to policies or override the get*AuthorizationResponse() methods.
  • Tables sort by primary key by default. Disable it with ->defaultKeySort(false) if your table has no key.
  • Import and export jobs now retry three times with a 60-second backoff, instead of hammering for 24 hours.
  • The Spatie Translatable plugin is deprecated. Switch to the Lara Zeus fork. The upgrade script suggests the Composer commands for this.

The API shape you’ll see after the script

After the script runs, your resources will look different. This is roughly what a v3 table and form look like in v4/v5, so you can recognise the result and write new code the same way:

use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;              // was Filament\Tables\Actions\EditAction
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Section;      // was Filament\Forms\Components\Section
use Filament\Schemas\Schema;                  // was Filament\Forms\Form
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;

public static function form(Schema $schema): Schema
{
    return $schema->components([                // was $form->schema([...])
        Section::make('Details')->schema([
            TextInput::make('name')->required(),
        ]),
    ]);
}

public static function table(Table $table): Table
{
    return $table
        ->columns([TextColumn::make('name')->searchable()])
        ->recordActions([EditAction::make()])   // was ->actions()
        ->toolbarActions([                      // was ->bulkActions()
            BulkActionGroup::make([DeleteBulkAction::make()]),
        ]);
}

Get and Set moved to Filament\Schemas\Components\Utilities. Infolists also use Schema now, and every action lives under Filament\Actions.

Migrate your theme to Tailwind CSS v4

If you have resources/css/filament/admin/theme.css, replace the old @config line with @source entries:

@import '../../../../vendor/filament/filament/resources/css/theme.css';

@source '../../../../app/Filament/**/*';
@source '../../../../resources/views/filament/**/*';
/* add paths from the old tailwind.config.js "content" array */

Then run Tailwind’s official upgrade tool and move any tailwind.config.js customisations into CSS:

npx @tailwindcss/upgrade
npm run build

If you never had a custom theme but used Tailwind classes in your own Filament views, create one now with php artisan make:filament-theme. Our Filament theming guide walks through it.

At this point, boot the app and run your tests on v4. Don’t move on until Pass 1 is green.

Pass 2: Filament v4 → v5

This is the short one:

composer remove filament/upgrade --dev
composer require filament/upgrade:"^5.0" -W --dev
vendor/bin/filament-v5

composer require filament/filament:"^5.0" -W --no-update
composer update
composer remove filament/upgrade --dev

Then work through the Livewire 4 changes that affect custom code: renamed config keys, wire:model.blur needing .live, closed <livewire:... /> tags, the removed wire:transition modifiers, and the new /livewire-{hash}/ endpoints. Our Filament v4 to v5 upgrade guide covers each one with search commands to find them.

Plugins: audit before you start, not halfway through

Plugin compatibility is the main reason v3 → v5 upgrades stall. Before Pass 1, list every Filament plugin and check it:

composer show | grep -i filament
composer why-not filament/filament 5.0

For each plugin, you’ll find one of three things:

  1. It supports ^4.0|^5.0. Just bump its constraint. Most major plugins are here, including Shield 4.x, Breezy, Filament Excel, Curator and Apex Charts.
  2. It has a v5-only major. Bump to that major and read its changelog. Shield 4.x, for example, is a full rewrite with new permission names.
  3. It’s abandoned. Replace it, or check whether v4/v5 core now does the job. Filament v4 added a TipTap rich editor, table-mode repeaters, built-in multi-factor authentication and slider and code editor fields. Several v3-era plugins became unnecessary.

Rollout checklist

  • Staging gets a copy of production data, with S3 credentials if you use private files.
  • Clear every cache: php artisan optimize:clear, then php artisan filament:optimize.
  • Rebuild front-end assets in CI, not on the server.
  • Update WAF/CDN rules for Livewire 4’s /livewire-{hash}/ paths.
  • Tell users about deferred filters and the new layout, or keep the v3 defaults with the snippet above.
  • Keep the v3 release tagged. Rollback means redeploying that tag, since the database schema only changes if you published and ran new Filament migrations (the imports/exports tables, for example).

FAQ

Can I upgrade Filament v3 directly to v5?

Yes, in one branch, but run the v4 upgrade script before the v5 script. The v5 script doesn’t contain the Rector rules that convert v3 code.

How long does a v3 to v5 upgrade take?

A small panel with a few resources and no custom theme typically takes half a day. Large panels with custom themes, many plugins and custom Livewire components can take several days, mostly spent on plugins and visual regressions.

Will my v3 resource classes still work?

After the v4 script runs, yes. It rewrites namespaces and method names. Behavioural defaults (deferred filters, layout spans, file visibility) change, but you can restore them with configureUsing().

Is Filament v3 still supported?

Only for security. Bug fixes ended on 1 August 2026. Security fixes continue until 1 January 2028, per the version support policy.

Do I have to migrate to the new directory structure?

No. It’s optional, and you can keep v3-style file generation with the file_generation flags. New projects and the docs use the new layout, though.

Sources and further reading

Related on The Web Tier: Filament v5 vs v4 · Best Filament plugins

TWT Staff

TWT Staff

Writes about Programming, tech news, discuss programming topics for web developers (and Web designers), and talks about SEO tools and techniques

Your experience on this site will be improved by allowing cookies Cookie Policy