Saltar al contenido principal

¿Qué es Inertia.js?

Quieres construir el frontend con React o Vue, pero deseas evitar diseñar, implementar y mantener una API por separado; el que resuelve este dilema es Inertia.js. Inertia es un “pegamento” que te permite escribir solo el frontend con React, Vue o Svelte, manteniendo tal cual el enrutamiento y los controladores del lado servidor. No es un framework, sino una capa adaptadora que conecta Laravel existente con los frameworks JavaScript.
La versión más reciente actualmente es Inertia v3 (lanzado el 26 de marzo de 2026). Los starter kits de Laravel 13 (React, Vue y Svelte) ya vienen compatibles con Inertia.

Diferencias con SPA y MPA tradicionales

ArquitecturaCaracterísticasRetos
MPA (aplicación Blade tradicional)Simple, fácil integración con LaravelRecarga completa en cada navegación
SPA (API + frontend separado)Alta interactividadGestión duplicada de diseño de API, autenticación y tipos
Inertia (monolito moderno)UX de SPA + sencillez del lado servidorCoste de aprendizaje propio
Con Inertia puedes pasar datos directamente desde los controladores de Laravel a componentes Vue o React. No hace falta definir una API REST, y como la navegación entre páginas se realiza mediante XHR en lugar de recarga completa del navegador, se consigue una sensación de operación fluida al estilo SPA.

Relación con los starter kits de Laravel

Al crear un proyecto con laravel new, si eliges React, Vue o Svelte, Inertia se configura automáticamente.
laravel new my-app
# Si en el prompt interactivo eliges React / Vue / Svelte, la estructura queda con Inertia
En los starter kits se prepara automáticamente lo siguiente.
  • inertiajs/inertia-laravel (adaptador del lado servidor)
  • @inertiajs/react / @inertiajs/vue3 / @inertiajs/svelte (adaptadores del lado cliente)
  • Middleware HandleInertiaRequests
  • Pantallas de login, registro y restablecimiento de contraseña (ya implementadas como componentes Inertia)
Si vas a incorporar Inertia manualmente en un proyecto existente, instala por separado la parte del servidor y la del cliente. Consulta el procedimiento de instalación en la documentación oficial para más detalles.

Fundamentos de Inertia::render()

Para devolver una respuesta Inertia desde un controlador de Laravel se usa Inertia::render(). En el primer argumento se indica el nombre del componente JavaScript y en el segundo, los datos que se pasan como props.
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'),
        ]);
    }
}
En lugar de Inertia::render() también puedes usar la función helper inertia(). Unifica la elección según el estilo del equipo.
El nombre de componente 'Posts/Index' corresponde a una ruta de archivo. En React, el componente correspondiente es resources/js/Pages/Posts/Index.jsx, y en Vue, resources/js/Pages/Posts/Index.vue.

Estructura de un componente de página

Los componentes de página de Inertia son componentes Vue/React normales. Los datos pasados desde el controlador se reciben como props.
React
// resources/js/Pages/Posts/Index.jsx
import { Link } from '@inertiajs/react'

export default function PostsIndex({ posts }) {
    return (
        <div>
            <h1>Lista de publicaciones</h1>
            {posts.data.map(post => (
                <article key={post.id}>
                    <h2>
                        <Link href={`/posts/${post.id}`}>{post.title}</Link>
                    </h2>
                </article>
            ))}
        </div>
    )
}
Vue
<!-- resources/js/Pages/Posts/Index.vue -->
<script setup>
import { Link } from '@inertiajs/vue3'

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

<template>
    <div>
        <h1>Lista de publicaciones</h1>
        <article v-for="post in posts.data" :key="post.id">
            <h2>
                <Link :href="`/posts/${post.id}`">{{ post.title }}</Link>
            </h2>
        </article>
    </div>
</template>
Al usar el componente <Link>, la navegación entre páginas se realiza por XHR, evitando la recarga completa. Se escribe exactamente igual que una etiqueta <a> normal, pero por debajo Inertia solo cambia el componente de página.

Datos compartidos — middleware HandleInertiaRequests

Los datos comunes que necesitan todas las páginas (información del usuario autenticado, mensajes flash, etc.) se definen en el método share() del middleware HandleInertiaRequests.
// 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'),
            ],
        ]);
    }
}
Los datos compartidos se fusionan automáticamente con las props de todas las páginas.
React
// Ejemplo de acceso desde un componente de layout
import { usePage } from '@inertiajs/react'

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

    return (
        <main>
            <header>
                {auth.user ? `Sesión iniciada: ${auth.user.name}` : 'Invitado'}
            </header>
            {flash.success && <div className="alert-success">{flash.success}</div>}
            <article>{children}</article>
        </main>
    )
}
Como los datos compartidos se incluyen en todas las peticiones, se recomienda limitarlos al mínimo necesario. Si los pasas mediante una evaluación diferida con fn(), se evaluarán solo en las peticiones que realmente los necesiten.

Envío de formularios y manejo de errores de validación

El procesamiento de formularios con Inertia se integra de forma natural con la validación de Laravel. Con el helper useForm() puedes implementar de forma sencilla la gestión del estado del formulario, el envío y la visualización de errores.

Lado del controlador

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', 'Se ha creado la publicación.');
    }
}
Cuando se produce un error de validación, Laravel redirige automáticamente a la página del formulario y guarda la información de error en la sesión. Inertia detecta esto automáticamente y lo pasa a la página como la prop errors.

Lado del frontend

React
// 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>Título</label>
                <input
                    value={data.title}
                    onChange={e => setData('title', e.target.value)}
                />
                {errors.title && <p className="error">{errors.title}</p>}
            </div>

            <div>
                <label>Contenido</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 ? 'Enviando...' : 'Publicar'}
            </button>
        </form>
    )
}
Vue
<!-- 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>Título</label>
            <input v-model="form.title" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenido</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 ? 'Enviando...' : 'Publicar' }}
        </button>
    </form>
</template>
Cuando se devuelve un error de validación, useForm() mantiene el contenido introducido y muestra el error. No hay que hacer que el usuario vuelva a introducir el formulario, lo que mejora la experiencia.

Casos de uso adecuados y no adecuados

Casos en los que Inertia es adecuado

  • Cuando un equipo que conoce bien Laravel quiere construir UIs al estilo SPA
  • Cuando se quiere gestionar centralizadamente autenticación, autorización y validación en el lado Laravel
  • Aplicaciones como paneles de administración o herramientas internas, con baja prioridad de SEO
  • Proyectos en los que se quiere evitar el coste de diseñar y mantener una API aparte

Casos en los que no es adecuado

  • Cuando múltiples clientes externos (apps móviles, etc.) usan la misma API
  • Sitios de contenido en los que el SEO es muy importante (se puede afrontar con SSR, pero se vuelve más complejo)
  • Configuraciones de microfrontends u otras en las que el frontend se desarrolla por un equipo totalmente independiente
Inertia también soporta Server-Side Rendering (SSR). Si hay páginas en las que se requiere SEO, considera la opción SSR. Los starter kits de Laravel también incluyen configuración de SSR.

Principales cambios de Inertia v3

Inertia v3 se lanzó el 26 de marzo de 2026. A continuación presentamos los principales cambios respecto a v2.

Eliminación de Axios: cliente XHR ligero integrado

En v3 se ha eliminado Axios y se ha sustituido por un cliente XHR ligero integrado. En la mayoría de aplicaciones no se necesitan cambios de código. Los interceptores de Axios pueden migrarse directamente a los interceptores integrados. Si sigues queriendo usar Axios, puedes utilizarlo mediante el adaptador de Axios.

Simplificación de SSR con el plugin @inertiajs/vite

Al introducir el nuevo plugin de Vite, la resolución automática de componentes de página y la configuración de SSR se simplifican enormemente. SSR durante el desarrollo funciona ahora con solo ejecutar npm run dev, sin necesidad de arrancar un servidor Node por separado.
npm install @inertiajs/vite@^3.0

Hook useHttp: peticiones HTTP sin cambio de página

El hook useHttp permite enviar peticiones HTTP al servidor sin provocar una navegación de página (Inertia visit). Es útil cuando quieres comunicarte manteniendo la página actual, como guardar desde un modal o procesamiento en segundo plano.

Actualizaciones optimistas (Optimistic Updates)

Se soportan las actualizaciones optimistas a nivel de useForm y de router. Actualiza la UI de inmediato sin esperar la respuesta del servidor y, si falla, hace rollback automáticamente.

Props de layout (Layout Props)

Con el hook useLayoutProps puedes pasar datos desde el componente de página al layout persistente. El “control de estado del layout específico de una página”, que antes solo podía apoyarse en datos compartidos o en props de página, ahora se escribe de forma sencilla.

Cambios de requisitos

En v3 se han elevado las versiones mínimas siguientes.
Elementov2v3
PHP8.1+8.2+
Laravel10+11+
React18+19+
Svelte4+5+

Eliminación de Inertia::lazy()

Inertia::lazy(), que estaba obsoleto en v2, se ha eliminado por completo en v3. En su lugar se usa Inertia::optional().
// v2 (obsoleto)
'users' => Inertia::lazy(fn () => User::all()),

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

Cambios en los nombres de eventos

v2v3
invalidhttpException
exceptionnetworkError

Eliminación de la opción future

Se ha eliminado el bloque de configuración future que en v2 se ofrecía como opción experimental. Todas esas opciones están ahora habilitadas por defecto. Elimina el bloque future de la configuración de createInertiaApp.
Para el procedimiento detallado de actualización desde v2, consulta la guía oficial de actualización. Para v2 se ofrecen correcciones de errores hasta el 26 de septiembre de 2026 y correcciones de seguridad hasta el 26 de marzo de 2027.

Conclusión

Inertia.js es una herramienta que responde a la necesidad realista de “quiero mantener Laravel tal cual y escribir el frontend con React/Vue”. Su mayor fortaleza es la sencillez de pasar datos directamente desde los controladores a los componentes sin diseñar una API. Que los starter kits de Laravel 13 soporten Inertia confirma también que su posición en el ecosistema Laravel está consolidada. Si Livewire es un enfoque para construir UIs dinámicas solo con PHP, Inertia es un enfoque que permite usar el poder de los frameworks JavaScript sin perder la sencillez del lado servidor. Cuál elegir depende del conjunto de habilidades del equipo y de los requisitos del proyecto, pero cuando se trata de “mantener los controladores de Laravel tal cual y construir la interfaz con React”, Inertia es la elección más natural.

Documentación oficial de Inertia.js

Para todas las funcionalidades de Inertia v3, consulta la documentación oficial.
Última modificación el 13 de julio de 2026