Filament v4 Unified Schema API: Forms &amp; Infolists | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com) [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles  ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

  [ home ](https://www.msaied.com)    [ articles ](https://www.msaied.com/articles)    Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API        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)

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

  #filament   #laravel   #filament-v4   #php  

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

     26 Jun 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why the Old Approach Felt Redundant  ](#why-the-old-approach-felt-redundant)
2. [  02   The Unified Schema API in Practice  ](#the-unified-schema-api-in-practice)
3. [  03   Opting Into Context-Specific Behaviour  ](#opting-into-context-specific-behaviour)
4. [  04   Reusable Schema Fragments  ](#reusable-schema-fragments)
5. [  05   Table Columns Are Still Separate  ](#table-columns-are-still-separate)
6. [  06   Testing the New Schema  ](#testing-the-new-schema)
7. [  07   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.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v4-schema-based-forms-infolists-and-the-unified-schema-api-1&text=Filament+v4+Schema-Based+Forms%2C+Infolists%2C+and+the+Unified+Schema+API) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v4-schema-based-forms-infolists-and-the-unified-schema-api-1) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  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. 

      Q02  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. 

      Q03  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. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://www.msaied.com/articles) 

 [ ![Laravel Pipeline Pattern: Building Custom Pipelines Beyond Middleware](https://cdn.msaied.com/296/afbac95c7f4aac1cee83eb2c87541369.png) laravel pipeline clean-architecture 

### Laravel Pipeline Pattern: Building Custom Pipelines Beyond Middleware

The Pipeline pattern in Laravel is far more powerful than middleware alone. Learn how to build typed, composab...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 26 Jun 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-pipeline-pattern-building-custom-pipelines-beyond-middleware-1) [ ![Read/Write Splitting, Connection Pooling, and Sticky Reads in Laravel](https://cdn.msaied.com/295/d977bd189583149245c03d6d763d9db5.png) laravel database performance 

### Read/Write Splitting, Connection Pooling, and Sticky Reads in Laravel

Learn how Laravel's database layer handles read/write splitting, when sticky reads matter, and how to layer Pg...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 26 Jun 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/readwrite-splitting-connection-pooling-and-sticky-reads-in-laravel-2) [ ![Laravel Service Container: Contextual Binding, Tagging, and Method Injection](https://cdn.msaied.com/294/e5b9d047bd33c3f8b80069ef6a178884.png) laravel service-container dependency-injection 

### Laravel Service Container: Contextual Binding, Tagging, and Method Injection

Go beyond basic binding. Learn how contextual binding resolves different implementations per consumer, how tag...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 26 Jun 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-service-container-contextual-binding-tagging-and-method-injection-1) 

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

Explore

- [Home](https://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
