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

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

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

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API        On this page       1. [  Why Filament v4 Introduced a Unified Schema API ](#why-filament-v4-introduced-a-unified-schema-api)
2. [  The Core Concept: Schema as a First-Class Object ](#the-core-concept-codeschemacode-as-a-first-class-object)
3. [  Field Resolution and State Hydration ](#field-resolution-and-state-hydration)
4. [  Practical Migration Pattern for Existing Resources ](#practical-migration-pattern-for-existing-resources)
5. [  Key Takeaways ](#key-takeaways)

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

  #filament   #laravel   #filament-v4   #admin-panel  

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

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

       Table of contents

1. [  01   Why Filament v4 Introduced a Unified Schema API  ](#why-filament-v4-introduced-a-unified-schema-api)
2. [  02   The Core Concept: Schema as a First-Class Object  ](#the-core-concept-codeschemacode-as-a-first-class-object)
3. [  03   Field Resolution and State Hydration  ](#field-resolution-and-state-hydration)
4. [  04   Practical Migration Pattern for Existing Resources  ](#practical-migration-pattern-for-existing-resources)
5. [  05   Key Takeaways  ](#key-takeaways)

 Why Filament v4 Introduced a Unified Schema API
-----------------------------------------------

In Filament v3, `form(Form $form)` and `infolist(Infolist $infolist)` lived in completely separate methods with separate component trees. Sharing layout logic between them meant either duplicating field arrays or reaching for abstract helper methods that felt bolted on.

Filament v4 solves this with the **Schema API**: a single component tree that both the form renderer and the infolist renderer consume. Fields declare how they behave in each context, and the framework resolves the correct representation at render time.

---

The Core Concept: `Schema` as a First-Class Object
--------------------------------------------------

Instead of returning a configured `Form` or `Infolist`, your resource now returns a `Schema`:

```php
use Filament\Schema\Schema;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Infolists\Components\TextEntry;

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

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

```

The `form()` and `infolist()` methods on the resource can now delegate to `schema()`, or you can override them individually when the display context genuinely differs.

```php
public static function form(Form $form): Form
{
    return $form->schema(static::schema(new Schema($form->getLivewire()))->getComponents());
}

public static function infolist(Infolist $infolist): Infolist
{
    return $infolist->schema([
        TextEntry::make('name'),
        TextEntry::make('status')
            ->badge()
            ->color(fn (Status $state) => $state->color()),
    ]);
}

```

When the infolist needs richer display logic (badges, icons, formatted values), you override it explicitly. When it doesn't, the shared schema is enough.

---

Field Resolution and State Hydration
------------------------------------

Under the hood, `Schema` components implement `HasState`. During form hydration, each component calls `$this->getState()` which reads from the Livewire component's `data` array. During infolist rendering, the same component tree reads from the bound `$record` model.

This dual-context resolution is why a `TextInput` can render as an `` in a form and as plain text in an infolist without you writing two components.

```php
// A custom field that behaves correctly in both contexts
class MoneyInput extends Field
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->formatStateUsing(fn ($state) => $state ? number_format($state / 100, 2) : null);
        $this->dehydrateStateUsing(fn ($state) => (int) (floatval(str_replace(',', '', $state)) * 100));
    }
}

```

`formatStateUsing` runs in both form and infolist contexts. `dehydrateStateUsing` only fires when the form is submitted — the infolist never calls it.

---

Practical Migration Pattern for Existing Resources
--------------------------------------------------

The safest migration path is incremental:

1. **Extract shared layout** into a static `baseSchema()` method returning a plain array.
2. **Keep `form()` and `infolist()` separate** until you've verified parity.
3. **Collapse to `schema()`** once the infolist no longer needs custom entries.

```php
private static function baseSchema(): array
{
    return [
        TextInput::make('title')->required(),
        TextInput::make('slug')->unique(ignoreRecord: true),
    ];
}

public static function form(Form $form): Form
{
    return $form->schema([
        ...static::baseSchema(),
        FileUpload::make('cover_image'),
    ]);
}

public static function infolist(Infolist $infolist): Infolist
{
    return $infolist->schema([
        TextEntry::make('title'),
        TextEntry::make('slug'),
        ImageEntry::make('cover_image'),
    ]);
}

```

This pattern keeps diffs reviewable and avoids a big-bang rewrite.

---

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

- The unified `Schema` API eliminates the primary source of duplication between forms and infolists in Filament v4.
- `formatStateUsing` and `dehydrateStateUsing` are context-aware; only dehydration is skipped in infolist rendering.
- Custom fields built on `Field` work in both contexts without modification if they respect the state lifecycle.
- Incremental migration via a shared `baseSchema()` array is safer than rewriting resources all at once.
- Override `form()` or `infolist()` explicitly when display requirements genuinely diverge — the unified API is a tool, not a mandate.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Ffilament-v4-schema-based-forms-infolists-and-the-unified-schema-api-3&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%2Fmsaied.com%2Farticles%2Ffilament-v4-schema-based-forms-infolists-and-the-unified-schema-api-3) 

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

  3 questions  

     Q01  Can I still define separate form() and infolist() methods in Filament v4?        Yes. The unified Schema API is additive. You can define a shared schema() method and delegate from form() and infolist(), or keep them fully separate when the display contexts differ significantly. 

      Q02  Does a custom Field component need changes to work in both form and infolist contexts?        Not if it follows the standard state lifecycle. formatStateUsing runs in both contexts; dehydrateStateUsing is only called on form submission. Fields that respect these hooks work in infolists without modification. 

      Q03  How does Filament v4 know whether to render a TextInput as an input or as plain text?        The Schema renderer checks the rendering context — form or infolist — and calls the appropriate view. Each component ships with both a form view and an infolist view; the framework selects the correct one based on which container is active. 

  Continue reading

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

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

 [ ![New in Laravel 13: First-Party Image Manipulation](https://cdn.msaied.com/427/504aed7f9f1c4a1cd411c7c4a4b6bc7c.png) Laravel 13 Image Manipulation PHP 

### New in Laravel 13: First-Party Image Manipulation

Laravel 13 introduces a first-party image manipulation feature, removing the need for third-party packages for...

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

 15 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/new-in-laravel-13-first-party-image-manipulation) [ ![Filament v4 Testing with Pest: Resources, Actions, and Form Assertions](https://cdn.msaied.com/426/a81430a378b2849b6fbecb8235b9119f.png) filament pest testing 

### Filament v4 Testing with Pest: Resources, Actions, and Form Assertions

A practical guide to testing Filament v4 panels using Pest — covering resource page assertions, table action d...

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

 15 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/filament-v4-testing-with-pest-resources-actions-and-form-assertions) [ ![Laravel Legacy Bridge: Carry Authenticated Sessions from a Legacy PHP App into Laravel](https://cdn.msaied.com/429/5abced4ee695d6c03e3ae41bbf2fe4bb.png) Laravel PHP Session Management 

### Laravel Legacy Bridge: Carry Authenticated Sessions from a Legacy PHP App into Laravel

Laravel Legacy Bridge is a package that reads a legacy session cookie, decodes the payload from the legacy dat...

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

 15 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-legacy-bridge-carry-authenticated-sessions-from-a-legacy-php-app-into-laravel) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://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://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://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)
