Filament v4 Unified Schema API: Forms &amp; Infolists | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API

 Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API
======================================================================

 Filament v4 replaces scattered form and infolist definitions with a single Schema API. Learn how unified schemas reduce duplication, enable reuse, and change how you structure Filament resources day-to-day.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 26 Jun 2026 · Updated 26 Jun 2026 · 3 min read

ShareCopy linkCopied

 ![Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API](https://cdn.msaied.com/297/6eb3a7aaf7148fd21116eea870bd004e.png) 

  On this page +1. [Why the Old Approach Felt Redundant](#why-the-old-approach-felt-redundant)
2. [The Unified Schema API in Practice](#the-unified-schema-api-in-practice)
3. [Opting Into Context-Specific Behaviour](#opting-into-context-specific-behaviour)
4. [Reusable Schema Fragments](#reusable-schema-fragments)
5. [Table Columns Are Still Separate](#table-columns-are-still-separate)
6. [Testing the New Schema](#testing-the-new-schema)
7. [Key Takeaways](#key-takeaways)

 Why the Old Approach Felt Redundant
-----------------------------------

In Filament v3, a typical resource forced you to define `form()` and `infolist()` separately. If your `OrderResource` displayed twelve fields, you wrote those fields twice — once as `TextInput` components, once as `TextEntry` components. The logic was identical; only the component class differed. Senior engineers reached for shared methods or traits to paper over the duplication, but it was always a workaround.

Filament v4 addresses this at the framework level with the **unified Schema API**.

The Unified Schema API in Practice
----------------------------------

The core idea: a `Schema` is a context-aware tree of components. The same schema definition renders as an editable form inside `CreateRecord` or `EditRecord`, and as a read-only infolist inside `ViewRecord`. Components resolve their own rendering based on the active context.

```php
use Filament\Schema\Schema;
use Filament\Schema\Components\TextInput;
use Filament\Schema\Components\Select;
use Filament\Schema\Components\Section;

public function schema(Schema $schema): Schema
{
    return $schema->components([
        Section::make('Customer')
            ->schema([
                TextInput::make('name')
                    ->required()
                    ->maxLength(255),

                Select::make('status')
                    ->options(OrderStatus::class)
                    ->required(),
            ]),
    ]);
}

```

You define `schema()` once on the resource. Filament resolves `TextInput` to an editable input on the form page and to a read-only text entry on the view page — no duplication, no trait gymnastics.

### Opting Into Context-Specific Behaviour

Sometimes a field genuinely needs different behaviour per context. The API provides `->visibleOn()` and `->hiddenOn()` helpers, plus the lower-level `->when()` callback that receives the active context string (`'form'`, `'infolist'`):

```php
TextInput::make('internal_notes')
    ->hiddenOn('infolist'),

Select::make('assigned_to')
    ->options(fn () => User::pluck('name', 'id'))
    ->when(
        fn (string $context) => $context === 'form',
        fn (Select $field) => $field->searchable()->preload()
    ),

```

This keeps the single-schema principle intact while giving you an escape hatch.

### Reusable Schema Fragments

Because a schema is just a PHP value, you can extract fragments into dedicated classes and compose them:

```php
class AddressSchema
{
    public static function make(): array
    {
        return [
            TextInput::make('street')->required(),
            TextInput::make('city')->required(),
            TextInput::make('postcode')->required(),
        ];
    }
}

// Inside your resource:
Section::make('Shipping Address')
    ->schema(AddressSchema::make()),

```

This is the pattern that replaces the old `getFormSchema()` / `getInfolistSchema()` split. One fragment, used everywhere.

### Table Columns Are Still Separate

It is worth being explicit: the unified Schema API covers **forms and infolists only**. Table column definitions remain in `table()` and have not been merged. This is intentional — table columns carry sorting, searching, and bulk-action concerns that do not map cleanly onto a field/entry duality.

### Testing the New Schema

Pest assertions against Filament v4 schemas use the same `livewire()` helper, but the component class changes:

```php
use function Pest\Livewire\livewire;

it('saves an order', function () {
    livewire(\App\Filament\Resources\OrderResource\Pages\CreateOrder::class)
        ->fillForm([
            'name' => 'Acme Corp',
            'status' => 'pending',
        ])
        ->call('create')
        ->assertHasNoFormErrors();
});

```

The assertion surface is unchanged; only the underlying schema resolution differs.

Key Takeaways
-------------

- **One `schema()` method** replaces separate `form()` and `infolist()` definitions on a resource.
- Components are **context-aware** — they render as inputs or entries depending on the active page.
- Use `->when()` or `->hiddenOn()` for the rare cases where context-specific behaviour is genuinely needed.
- Extract reusable fragments into plain PHP classes; they compose cleanly into any schema.
- Table columns remain separate — the unification is scoped to forms and infolists.
- Existing Pest assertions continue to work; no test-layer rewrite is required.

- [filament](https://www.msaied.com/public/articles?search=filament)
- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [filament-v4](https://www.msaied.com/public/articles?search=filament-v4)
- [php](https://www.msaied.com/public/articles?search=php)

 Frequently asked questions 
---------------------------

  Do I have to rewrite all my v3 resources to use the unified Schema API when upgrading to v4?Not immediately. Filament v4 provides compatibility shims so existing `form()` and `infolist()` definitions continue to work during migration. You can migrate resources incrementally, replacing both methods with a single `schema()` method at your own pace.

   Can a single schema component render completely differently in form vs infolist context?Yes. Each component resolves its own view based on the active context string. You can also use the `-&gt;when()` callback to apply arbitrary configuration — different options, validation rules, or visibility — depending on whether the schema is rendering as a form or an infolist.

   Does the unified Schema API affect how Filament handles validation?Validation rules are only evaluated in form context. When the same schema renders as an infolist, validation is skipped entirely. You do not need to guard your `-&gt;required()` or `-&gt;rules()` calls — Filament handles the context check internally.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleLaravel Pipeline Pattern: Building Custom Pipelines Beyond Middleware](https://www.msaied.com/public/articles/laravel-pipeline-pattern-building-custom-pipelines-beyond-middleware-1) [Next articleHelp Make Filament Faster: Beta Versions of v4 and v5 Now Available for Testing](https://www.msaied.com/public/articles/help-make-filament-faster-beta-versions-of-v4-and-v5-now-available-for-testing)  

   On this page
-------------

1. [Why the Old Approach Felt Redundant](#why-the-old-approach-felt-redundant)
2. [The Unified Schema API in Practice](#the-unified-schema-api-in-practice)
3. [Opting Into Context-Specific Behaviour](#opting-into-context-specific-behaviour)
4. [Reusable Schema Fragments](#reusable-schema-fragments)
5. [Table Columns Are Still Separate](#table-columns-are-still-separate)
6. [Testing the New Schema](#testing-the-new-schema)
7. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
