Introduction
Filament 4 is here, and if you're running a Laravel admin panel on Filament v3.3, upgrading brings a new Schema architecture, Tailwind CSS v4 support, and significant API improvements. We recently upgraded a production co-parenting app from Filament v3.3.45 to Filament v4.7.0 on Laravel 11, and this guide walks through every step — including the gotchas the official docs don't warn you about.
This guide covers the exact commands we ran, the errors we hit, and the manual fixes required after the automated Rector tool missed several breaking changes. If you've searched for "filament v4 migration guide", "filament 4 breaking changes", or "how to upgrade filament 3 to 4" — you're in the right place.
Prerequisites
Before starting, make sure you have:
| Requirement | Minimum Version |
|---|---|
| PHP | 8.2+ |
| Laravel | 11.x |
| Filament | 3.x (we started on 3.3.45) |
| Composer | 2.x |
| Git | Any recent version |
Important: Commit all your changes before running the upgrade. The Rector tool modifies files directly. You need a clean working tree to safely rollback if something goes wrong.
git add -A && git commit -m "chore: pre-filament-v4-upgrade snapshot"
We recommend creating a dedicated branch:
git checkout -b upgrade/filament-v4
Step 1: Install the Filament Upgrade Tool
Filament ships an automated upgrade package that uses Rector to handle most breaking changes across your codebase.
composer require filament/upgrade:"^4.0" -W --dev
This installs three dev dependencies:
filament/upgrade(v4.7.0)phpstan/phpstanrector/rector
Step 2: Run the Automated Filament v4 Upgrade (Rector)
The upgrade tool scans your Filament code and applies transformations automatically:
vendor/bin/filament-v4
Fix: "MissingInputException: Aborted" Error
If you're running this in a non-interactive terminal (CI/CD, scripts, or piped input), you'll hit this error:
Fatal error: Uncaught Symfony\Component\Console\Exception\MissingInputException: Aborted.
in vendor/symfony/console/Helper/QuestionHelper.php
The tool prompts for a directory list interactively. Fix it by piping an empty string to accept the default app directory:
echo "" | vendor/bin/filament-v4
You should see output like:
Start processing /app to fix code affected by breaking changes.
130/130 [============================] 100%
Finished processing /app.
What Rector Automatically Changes
In our project with 130 files (10 resources, 30 pages, 3 relation managers), Rector handled:
| Change | Before (v3) | After (v4) |
|---|---|---|
| Form method signature | Forms\Form $form | Schema $schema |
| Form return call | $form->schema([...]) | $schema->components([...]) |
| Table actions | ->actions([...]) | ->recordActions([...]) |
| Bulk actions | ->bulkActions([...]) | ->toolbarActions([...]) |
| Navigation icon type | ?string | string | \BackedEnum | null |
| Navigation group type | ?string | string | \UnitEnum | null |
| Import statements | Namespace aliases (Forms\Components\X) | Explicit imports (use Filament\Forms\Components\X) |
| Page class references | Pages\ListEvents::route(...) | ListEvents::route(...) with use import |
Step 3: Update Composer Dependencies to Filament v4
After Rector finishes, it tells you to run two commands:
composer require filament/filament:"^4.0" -W --no-update
composer update
Fix: "Source directory has uncommitted changes" Error
During composer update, you may encounter:
Source directory vendor/nesbot/carbon has uncommitted changes.
This happens when a vendor package (like nesbot/carbon) has local modifications in its .git directory. Fix it by resetting the vendor package:
cd vendor/nesbot/carbon && git checkout .
cd /path/to/your/project
composer update
After a successful update, verify the installed version:
composer show filament/filament
Expected output:
name : filament/filament
versions : * v4.7.0
New packages installed with Filament 4 include:
filament/schemas(the new Schema architecture)filament/query-builderchillerlan/php-qrcodeueberdosis/tiptap-phppragmarx/google2faandpragmarx/google2fa-qrcode
Step 4: Fix Breaking Changes Rector Misses
This is the critical step most guides skip. Rector does not catch everything. In our upgrade, three breaking changes were missed across three resource files. You need to search for these patterns manually.
Find All Remaining Issues
Run this grep across your Filament directory:
grep -rn "callable \$get\|callable \$set\|MultiSelect\|->reactive()\|->json()" app/Filament/
If you see matches, fix them as shown below.
4a. Replace reactive() with live()
The ->reactive() method has been removed in Filament 4. Replace it with ->live().
Before (Filament 3):
Select::make('repeat_type')
->options([...])
->default('none')
->reactive(),
After (Filament 4):
Select::make('repeat_type')
->options([...])
->default('none')
->live(),
Verify with PHP:
php -r "echo method_exists('Filament\Forms\Components\Select', 'reactive') ? 'exists' : 'REMOVED';"
# Output: REMOVED
4b. Replace callable $get with Get $get
Filament 4 replaces the generic callable type hint with a dedicated Filament\Forms\Get class for form state access.
Before (Filament 3):
use Filament\Forms;
// In closures:
->visible(fn (callable $get) => $get('repeat_type') === 'custom')
->visible(fn (callable $get) => $get('repeat_type') !== 'none')
After (Filament 4):
use Filament\Forms\Get;
// In closures:
->visible(fn (Get $get) => $get('repeat_type') === 'custom')
->visible(fn (Get $get) => $get('repeat_type') !== 'none')
Don't forget to add the use Filament\Forms\Get; import at the top of your file. The same applies to Filament\Forms\Set if you use $set closures.
4c. Replace MultiSelect with Select->multiple()
The MultiSelect component has been completely removed in Filament 4. It's now a mode of the standard Select component.
Before (Filament 3):
use Filament\Forms\Components\MultiSelect;
MultiSelect::make('children')
->relationship('children', 'name')
->label('Children'),
After (Filament 4):
use Filament\Forms\Components\Select;
Select::make('children')
->multiple()
->relationship('children', 'name')
->label('Children'),
Verify the class is truly gone:
php -r "echo class_exists('Filament\Forms\Components\MultiSelect') ? 'exists' : 'REMOVED';"
# Output: REMOVED
4d. Replace ->json() on TextColumn
The ->json() method on TextColumn has been removed in Filament 4. Replace it with formatStateUsing().
Before (Filament 3):
Tables\Columns\TextColumn::make('data')
->label('Vitals Data')
->json()
->limit(50),
After (Filament 4):
Tables\Columns\TextColumn::make('data')
->label('Vitals Data')
->formatStateUsing(fn ($state) => is_array($state) ? json_encode($state) : $state)
->limit(50),
Verify:
php -r "echo method_exists('Filament\Tables\Columns\TextColumn', 'json') ? 'exists' : 'REMOVED';"
# Output: REMOVED
Step 5: Re-publish Filament Assets and Config
Filament 4 ships entirely new frontend assets (Tailwind CSS v4, new JS bundles, Inter font files). Delete the old ones and regenerate:
rm -rf public/css/filament public/js/filament
php artisan filament:assets
The new assets include a public/js/filament/schemas/ directory (for the new Schema architecture), updated component JS files, and Inter font woff2 files under public/fonts/filament/.
Re-publish the config file:
rm config/filament.php
php artisan vendor:publish --tag=filament-config
The new config/filament.php has significantly more options than v3's version. Notably, default_filesystem_disk now defaults to env('FILESYSTEM_DISK', 'local'). If your file uploads use ->disk('public') explicitly on each component, you're fine. Otherwise, check this setting.
Step 6: Clear All Caches
php artisan cache:clear
php artisan config:clear
php artisan view:clear
php artisan route:clear
Step 7: Remove the Upgrade Tool
The upgrade package and its dependencies (Rector, PHPStan) are no longer needed:
composer remove filament/upgrade --dev
This removes filament/upgrade, rector/rector, and phpstan/phpstan from your dev dependencies.
Complete Summary of Breaking Changes
Here's a reference table of every breaking change we encountered:
| Breaking Change | Filament 3 | Filament 4 | Rector Auto-Fix? |
|---|---|---|---|
| Form method signature | form(Forms\Form $form): Forms\Form | form(Schema $schema): Schema | Yes |
| Schema method | $form->schema([...]) | $schema->components([...]) | Yes |
| Table row actions | ->actions([...]) | ->recordActions([...]) | Yes |
| Bulk actions | ->bulkActions([...]) | ->toolbarActions([...]) | Yes |
| Page class imports | Namespace-relative Pages\ListX | Explicit use imports | Yes |
| Navigation icon type hint | ?string | string | \BackedEnum | null | Yes |
reactive() | ->reactive() | ->live() | No |
| Closure type hints | fn (callable $get) | fn (Get $get) | No |
| MultiSelect component | MultiSelect::make() | Select::make()->multiple() | No |
| TextColumn json() | ->json() | ->formatStateUsing(fn ($state) => ...) | No |
Behavioral Changes (No Code Changes Needed)
These are new defaults in Filament 4 to be aware of:
- Table filters are deferred by default — users must click "Apply" to trigger filters. If you have no filters defined, no impact.
- Grid/Section components default to 1 column span — check your layouts if you use grid-based forms.
unique()validation ignores the current record by default — previously you had to add->ignorable($record)manually.- File visibility defaults to private on non-local disks — if you use S3 or similar, you may need to set
->visibility('public')explicitly.
Verification
After the upgrade, verify everything works:
# Check routes register without errors
php artisan route:list --path=admin
# Syntax check key files
php -l app/Filament/Resources/EventResource.php
php -l app/Filament/Resources/ExpenseResource.php
php -l app/Filament/Resources/VitalResource.php
# Confirm no remaining deprecated APIs
grep -rn "callable \$get\|MultiSelect\|->reactive()\|->json()" app/Filament/
Then test in the browser at /admin:
- All resource list pages load without errors
- Create and edit forms render correctly
- Conditional fields (using
->live()+->visible()) toggle properly - Multi-select relationship fields work
- File uploads function on the correct disk
- Relation managers (like SplitsRelationManager) render in edit views
- Browser console shows no JavaScript errors
Conclusion
Upgrading from Filament 3 to Filament 4 is straightforward if you follow the right sequence: run the automated Rector tool first, then manually fix the four patterns it misses (reactive(), callable $get, MultiSelect, and json()). The whole process took us under 30 minutes for a project with 10 resources, 30 pages, and 3 relation managers.
The key takeaway: don't trust Rector blindly. Always grep your codebase for the patterns listed above after running the automated tool. The errors you'll get at runtime (Method reactive() not found, Class MultiSelect not found) are cryptic if you don't know what replaced them.
Need help upgrading your Laravel admin panel or migrating to Filament 4? Get in touch to discuss your project, or explore our web development services to see how we build high-quality Laravel applications.
Search Terms and Keywords Used
The following exact terms, commands, and technical phrases were used during this upgrade and are included for SEO indexing:
Commands executed:
composer require filament/upgrade:"^4.0" -W --devvendor/bin/filament-v4echo "" | vendor/bin/filament-v4composer require filament/filament:"^4.0" -W --no-updatecomposer updatecomposer show filament/filamentcomposer remove filament/upgrade --devphp artisan filament:assetsphp artisan vendor:publish --tag=filament-configphp artisan cache:clearphp artisan config:clearphp artisan view:clearphp artisan route:clearphp artisan route:list --path=admin
Error messages resolved:
Symfony\Component\Console\Exception\MissingInputException: AbortedSource directory vendor/nesbot/carbon has uncommitted changesClass Filament\Forms\Components\MultiSelect not foundMethod reactive() does not existMethod json() does not exist on Filament\Tables\Columns\TextColumn
Technical terms and search keywords:
- upgrade filament 3 to filament 4
- filament v4 migration guide
- filament 4 breaking changes
- filament php upgrade guide
- filament 4 rector tool
- filament reactive to live
- filament MultiSelect removed
- filament callable $get to Get $get
- filament TextColumn json removed
- filament Schema architecture v4
- filament actions to recordActions
- filament bulkActions to toolbarActions
- filament Forms\Form to Filament\Schemas\Schema
- laravel filament admin panel upgrade
- filament 4 composer update
- filament v3.3.45 to v4.7.0
- filament 4 tailwind css v4
- filament 4 new features
- filament/schemas package
- filament/query-builder package
- filament default_filesystem_disk config
- filament 4 table filters deferred
- filament 4 unique validation ignores current record



