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 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%2Fwww.msaied.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%2Fwww.msaied.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://www.msaied.com/articles) 

 [ ![DDD Value Objects and DTOs in Laravel Without the Bloat](https://cdn.msaied.com/450/41688537085b86f102fd8c219a35319f.png) laravel ddd php 

### DDD Value Objects and DTOs in Laravel Without the Bloat

Learn how to implement domain-driven value objects and data transfer objects in Laravel using PHP 8.3 readonly...

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

 21 Jul 2026     1 min read  

  Read    

 ](https://www.msaied.com/articles/ddd-value-objects-and-dtos-in-laravel-without-the-bloat) [ ![Laravel + Python FastAPI: Image OCR Demo](https://cdn.msaied.com/447/5f3d87146fbf19957973cbc88c6c0155.png) Laravel Python FastAPI 

### Laravel + Python FastAPI: Image OCR Demo

Learn how to call a Python image OCR script from Laravel using FastAPI as the bridge. This premium tutorial wa...

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

 20 Jul 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-python-fastapi-image-ocr-demo) [ ![Scaffold Laravel Packages with the `laravel package` Command in Installer v5.31.0](https://cdn.msaied.com/449/522e744d3c7bae1f214c179a83ae5b88.png) Laravel Installer Package Development CLI 

### Scaffold Laravel Packages with the `laravel package` Command in Installer v5.31.0

Laravel Installer v5.31.0 introduces a `laravel package` command to scaffold packages from the CLI, automated...

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

 20 Jul 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/scaffold-laravel-packages-with-the-laravel-package-command-in-installer-v5310) 

   [  ![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)
