Why v5 Matters More Than a Minor Bump
Filament has shipped breaking changes with every major version, and v5 is no exception. The core team is using v5 to finish what the Schema API started in v4: a fully unified, typed component graph that removes the last remaining inconsistencies between forms, infolists, and table columns. If your panels are non-trivial, preparing now saves a painful weekend later.
Disclaimer: Filament v5 is not yet stable. Everything below is based on public GitHub discussions, the v5 development branch, and official RFC comments as of mid-2025. APIs may still shift before release.
The Biggest Architectural Shift: Schema-First Everything
In v4, forms and infolists adopted the Schema API but table columns remained on a parallel component tree. v5 collapses this — columns, filters, and actions will all be first-class Schema\Component descendants.
Practically, this means the ->columns() method on a table will accept the same component pipeline as ->schema() on a form. Shared concerns like visibility, disabled state, and hidden-when logic will live in one trait instead of three.
// v4 — two separate APIs
public static function form(Form $form): Form
{
return $form->schema([
TextInput::make('name')->required(),
]);
}
public static function table(Table $table): Table
{
return $table->columns([
TextColumn::make('name')->sortable(),
]);
}
// v5 — columns gain full Schema lifecycle hooks
public static function table(Table $table): Table
{
return $table->columns([
TextColumn::make('name')
->sortable()
->visible(fn (Model $record): bool => $record->is_active)
->extraAttributes(['data-cy' => 'name-cell']), // now works on columns too
]);
}
Deprecated Patterns to Clean Up Now
1. ->disabledOn() / ->hiddenOn() String Context Checks
Passing string context names ('create', 'edit') is being replaced by explicit closure-based checks. Start migrating:
// Before (v3/v4 style)
TextInput::make('slug')->disabledOn('edit'),
// After (v5-ready)
TextInput::make('slug')
->disabled(fn (string $operation): bool => $operation === 'edit'),
2. Static getRelations() / getWidgets() Arrays
These are moving to a fluent panel builder registration pattern. If you override them in every resource, consider abstracting into a base resource class now:
abstract class BaseResource extends Resource
{
protected static function defaultRelations(): array
{
return [];
}
public static function getRelations(): array
{
return array_merge(static::defaultRelations(), [
AuditRelationManager::class,
]);
}
}
This pattern survives the v5 migration because the override point is in one place.
3. Custom Field getView() Without a Component Class
Blade-only custom fields that rely on getView() returning a string are being deprecated in favour of anonymous Livewire components or full Component subclasses. Audit your plugin fields:
grep -r 'getView()' app/Filament --include='*.php'
Any hit that returns a raw view string needs a Component wrapper before v5.
Testing Strategy During the Transition
Before upgrading, lock your Pest feature tests against the current behaviour so regressions surface immediately:
it('renders the name column on the user table', function () {
livewire(ListUsers::class)
->assertCanSeeTableRecords(User::factory(3)->create())
->assertTableColumnExists('name');
});
These assertions are stable across v4 and the current v5 beta because they test behaviour, not internal component structure.
Practical Preparation Checklist
- Audit
disabledOn/hiddenOnstring usage — replace with closures. - Centralise relation manager registration in a base resource.
- Replace Blade-only custom fields with proper
Componentsubclasses. - Pin your Filament version in
composer.json("filament/filament": "^4.0") and monitor the v5 changelog. - Run
php artisan filament:upgradeon a branch as soon as a stable beta lands. - Write table column existence tests now so you catch regressions during the upgrade.
Key Takeaways
- v5 unifies the Schema API across forms, infolists, and table columns — one component tree to rule them all.
- String-based context checks (
disabledOn,hiddenOn) are on their way out; closures are the future. - Custom Blade-only fields need to become proper
Componentsubclasses before v5. - Behaviour-focused Pest tests are your safety net during the upgrade.
- Centralising resource boilerplate in a base class dramatically reduces the surface area of breaking changes.