> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Costruire una SPA con Inertia.js

> Presentiamo Inertia.js v3, che collega il backend Laravel al frontend Vue/React/Svelte. Spiega in modo pratico il meccanismo per realizzare una SPA senza API, i componenti di pagina, i dati condivisi e la gestione dei form.

## Cos'è Inertia.js

Vuoi realizzare il frontend con React o Vue. Ma vuoi evitare di progettare, implementare e mantenere un'API a parte: la soluzione a questo dilemma è **Inertia.js**.

Inertia lascia intatti il routing e i controller lato server e ti permette di scrivere solo il frontend in React, Vue o Svelte, funzionando come una "colla". Non è un framework, ma un livello adattatore che collega Laravel esistente e i framework JavaScript.

<Info>
  L'ultima versione attuale è Inertia v3 (rilasciata il 26 marzo 2026). Gli starter kit di Laravel 13 (React, Vue, Svelte) sono già compatibili con Inertia.
</Info>

### Differenze rispetto a SPA e MPA tradizionali

| Architettura                   | Caratteristiche                           | Problemi                                                             |
| ------------------------------ | ----------------------------------------- | -------------------------------------------------------------------- |
| MPA (app Blade tradizionale)   | Semplice, facile da integrare con Laravel | Full reload a ogni transizione di pagina                             |
| SPA (API + frontend separati)  | Alta interattività                        | Doppia gestione di design API, autenticazione e definizioni dei tipi |
| **Inertia (monolite moderno)** | UX di SPA + semplicità lato server        | Ha un costo di apprendimento proprio                                 |

Usando Inertia puoi passare dati direttamente dai controller Laravel ai componenti Vue o React. Non è necessario definire un'API REST e anche le transizioni di pagina avvengono via XHR anziché con full reload del browser, ottenendo una sensazione fluida da SPA.

***

## Relazione con gli starter kit Laravel

Quando crei un progetto con `laravel new` e scegli React, Vue o Svelte, Inertia viene configurato automaticamente.

```shell theme={null}
laravel new my-app
# Il prompt interattivo con React / Vue / Svelte crea una configurazione Inertia
```

Negli starter kit viene predisposto automaticamente quanto segue.

* `inertiajs/inertia-laravel` (adapter lato server)
* `@inertiajs/react` / `@inertiajs/vue3` / `@inertiajs/svelte` (adapter lato client)
* Middleware `HandleInertiaRequests`
* Schermate di autenticazione come login, registrazione e reset password (già implementate come componenti Inertia)

Per introdurre Inertia manualmente in un progetto esistente, installa separatamente lato server e lato client. Per i dettagli fai riferimento alle istruzioni di installazione della documentazione ufficiale.

***

## Le basi di `Inertia::render()`

Per restituire una risposta Inertia da un controller Laravel usa `Inertia::render()`. Come primo argomento specifichi il nome del componente JavaScript, come secondo i dati da passare come prop.

```php theme={null}
use Inertia\Inertia;

class PostController extends Controller
{
    public function index()
    {
        return Inertia::render('Posts/Index', [
            'posts' => Post::latest()->paginate(10),
        ]);
    }

    public function show(Post $post)
    {
        return Inertia::render('Posts/Show', [
            'post' => $post->only('id', 'title', 'content', 'created_at'),
            'author' => $post->user->only('id', 'name'),
        ]);
    }
}
```

<Tip>
  In alternativa a `Inertia::render()` puoi usare la funzione helper `inertia()`. Quale usare va uniformato allo stile del team.
</Tip>

Il nome del componente `'Posts/Index'` corrisponde a un percorso di file. In React è `resources/js/Pages/Posts/Index.jsx`, in Vue `resources/js/Pages/Posts/Index.vue`.

***

## Struttura del componente di pagina

I componenti di pagina di Inertia sono normali componenti Vue/React. I dati passati dal controller vengono ricevuti come prop.

```jsx React theme={null}
// resources/js/Pages/Posts/Index.jsx
import { Link } from '@inertiajs/react'

export default function PostsIndex({ posts }) {
    return (
        <div>
            <h1>Elenco dei post</h1>
            {posts.data.map(post => (
                <article key={post.id}>
                    <h2>
                        <Link href={`/posts/${post.id}`}>{post.title}</Link>
                    </h2>
                </article>
            ))}
        </div>
    )
}
```

```vue Vue theme={null}
<!-- resources/js/Pages/Posts/Index.vue -->
<script setup>
import { Link } from '@inertiajs/vue3'

defineProps({
    posts: Object,
})
</script>

<template>
    <div>
        <h1>Elenco dei post</h1>
        <article v-for="post in posts.data" :key="post.id">
            <h2>
                <Link :href="`/posts/${post.id}`">{{ post.title }}</Link>
            </h2>
        </article>
    </div>
</template>
```

Con il componente `<Link>` le transizioni avvengono via XHR, evitando il full reload della pagina. Si scrive esattamente come un normale tag `<a>`, ma dietro le quinte Inertia sostituisce solo il componente di pagina.

***

## Dati condivisi — middleware `HandleInertiaRequests`

I dati necessari a tutte le pagine (utente loggato, messaggi flash, ecc.) si definiscono nel metodo `share()` del middleware `HandleInertiaRequests`.

```php theme={null}
// app/Http/Middleware/HandleInertiaRequests.php
use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'appName' => config('app.name'),

            'auth' => [
                'user' => $request->user()
                    ? $request->user()->only('id', 'name', 'email')
                    : null,
            ],

            'flash' => [
                'success' => $request->session()->get('success'),
                'error' => $request->session()->get('error'),
            ],
        ]);
    }
}
```

I dati condivisi vengono mergiati automaticamente nelle prop di tutte le pagine.

```jsx React theme={null}
// Esempio di accesso da un componente Layout
import { usePage } from '@inertiajs/react'

export default function Layout({ children }) {
    const { auth, flash } = usePage().props

    return (
        <main>
            <header>
                {auth.user ? `Loggato come: ${auth.user.name}` : 'Ospite'}
            </header>
            {flash.success && <div className="alert-success">{flash.success}</div>}
            <article>{children}</article>
        </main>
    )
}
```

<Info>
  Poiché i dati condivisi sono inclusi in ogni richiesta, ti consigliamo di limitarli allo stretto necessario. Se usi valutazioni lazy con `fn()`, verranno valutati solo nelle richieste che li richiedono davvero.
</Info>

***

## Invio dei form e gestione degli errori di validazione

La gestione dei form con Inertia si integra naturalmente con la validazione di Laravel. Usando l'helper `useForm()` puoi implementare in modo semplice la gestione dello stato, l'invio e la visualizzazione degli errori.

### Lato controller

```php theme={null}
class PostController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'   => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
        ]);

        Post::create($validated + ['user_id' => auth()->id()]);

        return redirect()->route('posts.index')
            ->with('success', 'Post creato con successo.');
    }
}
```

In caso di errore di validazione, Laravel reindirizza automaticamente alla pagina del form e salva le informazioni sull'errore in sessione. Inertia lo rileva automaticamente e passa i dati alla pagina come prop `errors`.

### Lato frontend

```jsx React theme={null}
// resources/js/Pages/Posts/Create.jsx
import { useForm } from '@inertiajs/react'

export default function PostsCreate() {
    const { data, setData, post, processing, errors } = useForm({
        title: '',
        content: '',
    })

    function handleSubmit(e) {
        e.preventDefault()
        post('/posts')
    }

    return (
        <form onSubmit={handleSubmit}>
            <div>
                <label>Titolo</label>
                <input
                    value={data.title}
                    onChange={e => setData('title', e.target.value)}
                />
                {errors.title && <p className="error">{errors.title}</p>}
            </div>

            <div>
                <label>Contenuto</label>
                <textarea
                    value={data.content}
                    onChange={e => setData('content', e.target.value)}
                />
                {errors.content && <p className="error">{errors.content}</p>}
            </div>

            <button type="submit" disabled={processing}>
                {processing ? 'Invio in corso...' : 'Pubblica'}
            </button>
        </form>
    )
}
```

```vue Vue theme={null}
<!-- resources/js/Pages/Posts/Create.vue -->
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
    title: '',
    content: '',
})

function submit() {
    form.post('/posts')
}
</script>

<template>
    <form @submit.prevent="submit">
        <div>
            <label>Titolo</label>
            <input v-model="form.title" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenuto</label>
            <textarea v-model="form.content"></textarea>
            <p v-if="form.errors.content" class="error">{{ form.errors.content }}</p>
        </div>

        <button type="submit" :disabled="form.processing">
            {{ form.processing ? 'Invio in corso...' : 'Pubblica' }}
        </button>
    </form>
</template>
```

Quando arrivano errori di validazione, `useForm()` mostra gli errori mantenendo i contenuti inseriti. Non serve reinserire tutto e l'esperienza utente migliora.

***

## Casi d'uso adatti e non adatti

### Casi in cui Inertia è adatto

* Team che conoscono bene Laravel e vogliono realizzare UI in stile SPA
* Volere gestire in modo centralizzato lato Laravel autenticazione, autorizzazione e validazione
* App con SEO non prioritario, come pannelli di amministrazione o strumenti interni
* Progetti in cui vuoi evitare il costo di progettare e mantenere un'API separata

### Casi in cui non è adatto

* Quando più client esterni (app mobile, ecc.) usano la stessa API
* Siti di contenuti in cui la SEO è molto importante (gestibile con SSR ma complesso)
* Configurazioni micro-frontend, in cui il frontend è sviluppato da team completamente indipendenti

<Tip>
  Inertia supporta anche il Server-Side Rendering (SSR). Se ci sono pagine che richiedono SEO, considera l'opzione SSR. Anche gli starter kit di Laravel includono la configurazione SSR.
</Tip>

***

## Principali modifiche di Inertia v3

Inertia v3 è stato rilasciato il 26 marzo 2026. Ecco le principali novità rispetto a v2.

### Rimozione di Axios — verso un client XHR integrato leggero

In v3 Axios è stato rimosso e sostituito da un client XHR integrato più leggero. Nella maggior parte delle applicazioni non serve modificare il codice. Gli interceptor di Axios possono essere migrati direttamente sugli interceptor integrati. Se vuoi continuare a usare Axios, puoi farlo tramite un adapter Axios.

### Semplificazione dell'SSR con il plugin `@inertiajs/vite`

Introducendo il nuovo plugin Vite, la risoluzione automatica dei componenti di pagina e la configurazione SSR risultano notevolmente semplificate. L'SSR in sviluppo funziona semplicemente eseguendo `npm run dev`, senza dover avviare un server Node separato.

```bash theme={null}
npm install @inertiajs/vite@^3.0
```

### Hook `useHttp` — richieste HTTP senza transizione di pagina

Con l'hook `useHttp` puoi inviare richieste HTTP al server senza generare una transizione (visit Inertia). Utile quando vuoi comunicare mantenendo la pagina corrente, come per il salvataggio da un modale o per elaborazioni in background.

### Aggiornamenti UI ottimistici (Optimistic Updates)

Sono supportati gli aggiornamenti ottimistici a livello di `useForm` e di router. La UI viene aggiornata immediatamente senza attendere la risposta del server e, in caso di fallimento, viene automaticamente rollbackata.

### Layout Props

Con l'hook `useLayoutProps` puoi passare dati da un componente di pagina a un layout persistente. Il "controllo dello stato del layout per una pagina specifica", che prima poteva basarsi solo sui dati condivisi o sulle prop di pagina, ora si scrive in modo semplice.

### Cambiamenti nei requisiti

In v3 sono state innalzate le versioni minime seguenti.

| Elemento | v2   | v3   |
| -------- | ---- | ---- |
| PHP      | 8.1+ | 8.2+ |
| Laravel  | 10+  | 11+  |
| React    | 18+  | 19+  |
| Svelte   | 4+   | 5+   |

### Rimozione di `Inertia::lazy()`

`Inertia::lazy()`, deprecato in v2, è stato completamente rimosso in v3. Al suo posto si usa `Inertia::optional()`.

```php theme={null}
// v2 (deprecato)
'users' => Inertia::lazy(fn () => User::all()),

// v3
'users' => Inertia::optional(fn () => User::all()),
```

### Rinomina degli eventi

| v2          | v3              |
| ----------- | --------------- |
| `invalid`   | `httpException` |
| `exception` | `networkError`  |

### Rimozione dell'opzione `future`

Il blocco di configurazione `future`, fornito in v2 come opzione sperimentale, è stato rimosso. Tutte quelle opzioni sono ora abilitate per impostazione predefinita. Rimuovi il blocco `future` dalla configurazione di `createInertiaApp`.

<Info>
  Per i dettagli sulla procedura di aggiornamento da v2 consulta la <a href="https://inertiajs.com/docs/v3/getting-started/upgrade-guide">guida ufficiale di aggiornamento</a>. Per v2 le bug fix sono fornite fino al 26 settembre 2026 e le correzioni di sicurezza fino al 26 marzo 2027.
</Info>

***

## Conclusioni

Inertia.js è uno strumento che risponde all'esigenza concreta di "voler tenere Laravel così com'è e scrivere il frontend in React/Vue". La sua forza principale è la semplicità di passare dati direttamente dal controller ai componenti senza progettare un'API.

Il fatto che gli starter kit di Laravel 13 supportino Inertia dimostra come la sua posizione nell'ecosistema Laravel sia ormai consolidata. Se Livewire è l'approccio per creare UI dinamiche solo con PHP, Inertia è l'approccio che permette di usare la potenza dei framework JavaScript senza rinunciare alla semplicità del lato server.

Quale scegliere dipende dalle competenze del team e dai requisiti del progetto, ma quando vuoi "mantenere i controller Laravel e realizzare le schermate in React", Inertia è la scelta più naturale.

<Card title="Documentazione ufficiale di Inertia.js" icon="book-open" href="https://inertiajs.com">
  Per tutte le funzionalità di Inertia v3 fai riferimento alla documentazione ufficiale.
</Card>


## Related topics

- [Introduzione a Vue.js — le basi per usarlo con Inertia × Laravel](/it/blog/vue-introduction.md)
- [Introduzione a React — le basi per usarlo con Inertia × Laravel](/it/blog/react-introduction.md)
- [Frontend](/it/frontend.md)
- [Installazione](/it/installation.md)
- [Introduzione all'autenticazione](/it/authentication.md)
