Saltar al contenido principal

¿Qué es Wayfinder?

Laravel Wayfinder es un paquete que conecta backend Laravel y frontend TypeScript con cero fricción. Genera automáticamente funciones TypeScript completamente tipadas a partir de controladores y rutas, con lo que puedes invocar directamente como funciones los endpoints de Laravel desde el código de frontend. Ya no es necesario hardcodear URLs, gestionar manualmente los parámetros de ruta ni sincronizar a mano los cambios del backend.
Wayfinder está en versión Beta (actualmente v0.1.x). La API puede cambiar antes de la release de v1.0.0. Todos los cambios importantes se registran en el CHANGELOG.

Diferencias entre Ziggy y Wayfinder

¿Qué es Ziggy?

Ziggy es un helper de rutas ampliamente usado durante años en el ecosistema Laravel. Publicaba las definiciones de rutas de Laravel al lado JavaScript, y permitía generar URLs con formas como route('posts.show', { id: 1 }).

Por qué se ha sustituido por Wayfinder

Ziggy trata los nombres de rutas y los parámetros como cadenas, por lo que tenía limitaciones de compatibilidad con TypeScript. Los typos en nombres de rutas o los nombres de parámetro incorrectos solo se convierten en errores en tiempo de ejecución. Wayfinder tiene un diseño TypeScript-first y genera los métodos de controlador como funciones importables.
ElementoZiggyWayfinder
Referencia a rutasroute('posts.show', { id: 1 })import { show } from "@/actions/..."
Seguridad de tiposDefiniciones de tipo limitadasTipos TypeScript completos
Soporte IDEAutocompletado débilAutocompletado y verificación de tipos completos
Tree-shakingTodas las rutas se incluyen en el bundleSolo las rutas usadas van al bundle
Momento de generaciónSe inyectan en runtimeGeneración estática en tiempo de build
En los starter kits de Laravel basados en Inertia (React, Vue, Svelte), Wayfinder se adopta por defecto.

Instalación

1. Instala el paquete del lado servidor con Composer

composer require laravel/wayfinder

2. Instala el plugin de Vite con NPM

npm i -D @laravel/vite-plugin-wayfinder

3. Añade el plugin a vite.config.js

import { wayfinder } from "@laravel/vite-plugin-wayfinder";
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";

export default defineConfig({
    plugins: [
        laravel({
            input: ["resources/js/app.ts"],
            refresh: true,
        }),
        wayfinder(),
    ],
});
Al añadir el plugin de Vite, mientras el servidor de desarrollo esté arrancado, se regeneran automáticamente los archivos TypeScript cada vez que cambian archivos PHP o de rutas.

Generación del archivo de definiciones TypeScript

Con el comando wayfinder:generate se generan los archivos TypeScript.
php artisan wayfinder:generate
Por defecto se generan tres directorios bajo resources/js.
resources/js/
├── actions/         # Funciones de acciones de controlador
│   └── App/Http/Controllers/
│       └── PostController.ts
├── routes/          # Funciones de rutas con nombre
│   └── post.ts
└── wayfinder/       # Archivo de definiciones de tipo
    └── types.ts
Como los archivos generados se regeneran completamente en cada build, se recomienda añadirlos a .gitignore. Excluye a la vez los tres directorios wayfinder, actions y routes.
Para cambiar el destino de salida, usa la opción --path.
php artisan wayfinder:generate --path=resources/js/api
También es posible generar solo las acciones de controlador o solo las rutas.
php artisan wayfinder:generate --skip-actions  # Solo genera rutas
php artisan wayfinder:generate --skip-routes   # Solo genera acciones

Uso básico

Importar y usar acciones

Ejemplo de generación de la URL correspondiente al método show de PostController.
import { show } from "@/actions/App/Http/Controllers/PostController";

show(1);
// { url: "/posts/1", method: "get" }
Si solo necesitas la URL, usa .url().
show.url(1); // "/posts/1"
También puedes indicar un método HTTP concreto.
show.head(1); // { url: "/posts/1", method: "head" }

Cómo pasar parámetros

Las funciones de Wayfinder aceptan parámetros en varios formatos.
import { update } from "@/actions/App/Http/Controllers/PostController";

// Parámetro único
show(1);
show({ id: 1 });

// Varios parámetros
update([1, 2]);
update({ post: 1, author: 2 });
update({ post: { id: 1 }, author: { id: 2 } });
Si la ruta especifica un key binding (/posts/{post:slug}), puedes usar ese valor.
// Si la ruta es /posts/{post:slug}
show("my-new-post");
show({ slug: "my-new-post" });

Importación de todo el controlador

También puedes importar todo el controlador y llamar a los métodos.
import PostController from "@/actions/App/Http/Controllers/PostController";

PostController.show(1);
PostController.index();
Al importar el controlador entero, el tree-shaking no funciona y todas las acciones se incluyen en el bundle. Importarlas por separado mantiene menor el tamaño final del bundle.

Controladores de acción única

En los controladores de acción única (Invokable Controller), llamas directamente a la función importada.
import StorePostController from "@/actions/App/Http/Controllers/StorePostController";

StorePostController(); // { url: "/posts", method: "post" }

Importar rutas con nombre

Para acceder por nombre de ruta, usa los archivos bajo routes/.
import { show } from "@/routes/post";

// Si el nombre de la ruta es `post.show`
show(1); // { url: "/posts/1", method: "get" }

Parámetros de consulta

Todas las funciones Wayfinder pueden añadir parámetros de consulta con la opción query.
import { show } from "@/actions/App/Http/Controllers/PostController";

show(1, { query: { page: 1, sort_by: "name" } });
// { url: "/posts/1?page=1&sort_by=name", method: "get" }
Para fusionar con los parámetros de consulta de la URL actual, usa mergeQuery.
// URL actual: /posts/1?page=1&sort_by=category&q=shirt

show.url(1, { mergeQuery: { page: 2, sort_by: "name" } });
// "/posts/1?page=2&sort_by=name&q=shirt"

// Para eliminar un parámetro, indica null
show.url(1, { mergeQuery: { sort_by: null } });
// "/posts/1?page=1&q=shirt"

Variante Form

Si vas a usarlo con formularios HTML tradicionales, genera con la opción --with-form y usa la variante .form.
php artisan wayfinder:generate --with-form
import { store, update } from "@/actions/App/Http/Controllers/PostController";

// Ejemplo con React
const Page = () => (
    <form {...store.form()}>
        {/* <form action="/posts" method="post"> */}
    </form>
);

const EditPage = () => (
    <form {...update.form(1)}>
        {/* <form action="/posts/1?_method=PATCH" method="post"> */}
    </form>
);

Combinar Inertia y Wayfinder

Al combinar los helpers de formulario de Inertia con Wayfinder, puedes enviar formularios sin escribir ni una cadena de URL.
import { useForm } from "@inertiajs/react";
import { store } from "@/actions/App/Http/Controllers/PostController";

const form = useForm({ name: "My Post" });

form.submit(store()); // Envía a POST /posts
También se puede usar en el componente Link.
import { Link } from "@inertiajs/react";
import { show } from "@/actions/App/Http/Controllers/PostController";

const Nav = () => (
    <Link href={show(1)}>Ver publicación</Link>
);

Adopción en los starter kits

Al crear un proyecto nuevo con laravel new y elegir React, Vue o Svelte, se te ofrece una configuración con Wayfinder ya configurado automáticamente. El starter kit incluye:
  • Paquete Composer laravel/wayfinder
  • Paquete NPM @laravel/vite-plugin-wayfinder
  • Configuración del plugin ya presente en vite.config.js
  • Directorios generados ya añadidos a .gitignore
También puedes hacer la introducción manual en proyectos existentes siguiendo los pasos anteriores.

Tratamiento de nombres de método que chocan con palabras reservadas

A los métodos de controlador con el mismo nombre que palabras reservadas de JavaScript como delete o import, se les añade el sufijo Method.
// Si el controlador tiene un método delete
import { deleteMethod } from "@/actions/App/Http/Controllers/PostController";

deleteMethod(1); // { url: "/posts/1", method: "delete" }

Estado actual (v0.1.x)

La versión estable actual se ofrece en la rama v0.1.x. A fecha de marzo de 2026, la última versión es v0.1.15.

Historial principal de la serie v0.1.x

VersiónContenido principal
v0.1.15Compatibilidad con Laravel 13, corrección de crash de vistas Blade
v0.1.13Mejora de compatibilidad TypeScript strict de los parámetros de consulta
v0.1.7Soporte para indicar los parámetros de URL por defecto desde el frontend
v0.1.6Añadido del plugin de Vite
v0.1.5Soporte de PHP 8.2, soporte de rutas cacheadas
v0.1.0Release inicial

Funcionalidades de nueva generación en desarrollo en la rama next

En la rama next se está desarrollando la próxima versión, que amplía notablemente las funcionalidades respecto a la actual v0.1.x.
La rama next se puede instalar con la restricción dev-next, pero la API puede cambiar mucho. No se recomienda su uso en producción.
composer require laravel/wayfinder:dev-next

Amplio aumento del alcance del TypeScript generado

Mientras que la v0.1.x se centra solo en rutas y acciones de controlador, la próxima versión genera como TypeScript todo lo siguiente.

Generación de tipos TypeScript de Form Request

class StorePostRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title'   => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
            'tags'    => ['nullable', 'array'],
            'tags.*'  => ['string'],
        ];
    }
}
A partir del Form Request anterior se genera el siguiente tipo.
export type Request = {
    title: string;
    content: string;
    tags?: string[] | null;
};

Generación de tipos de modelos Eloquent

class User extends Model
{
    protected $casts = [
        'email_verified_at' => 'datetime',
        'is_admin' => 'boolean',
    ];

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}
A partir del modelo anterior se generan los tipos en types.d.ts.
export namespace App.Models {
    export type User = {
        id: number;
        name: string;
        email: string;
        email_verified_at: string | null;
        is_admin: boolean;
        posts: App.Models.Post[];
    };
}

Conversión de Enum PHP a TypeScript

enum PostStatus: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}
Se generan tanto los tipos como las constantes.
// Definición de tipo (types.d.ts)
export namespace App.Enums {
    export type PostStatus = "draft" | "published" | "archived";
}

// Constantes (App/Enums/PostStatus.ts)
export const Draft = "draft";
export const Published = "published";
export const Archived = "archived";

export const PostStatus = { Draft, Published, Archived } as const;

Cambio del directorio de salida

En v0.1.x se dividía en tres directorios actions/, routes/ y wayfinder/, pero en la próxima versión se agrupa bajo resources/js/wayfinder.
resources/js/wayfinder/
├── App/Http/Controllers/
│   └── PostController.ts    # Funciones de acción (se elimina actions/)
├── routes/
│   └── post.ts              # Rutas con nombre (igual)
├── broadcast-channels.ts    # Canales de broadcast
├── broadcast-events.ts      # Eventos de broadcast
└── types.d.ts               # Todas las definiciones de tipo (cambiado desde types.ts)

Principales cambios de v0.1.x a next

  • La ruta de importación cambia de @/actions/... a @/wayfinder/...
  • Las flags --skip-actions, --skip-routes y --with-form se eliminan y pasan al archivo de configuración
  • types.ts cambia a types.d.ts

Conclusión

Laravel Wayfinder es un paquete que rediseña con enfoque TypeScript-first la funcionalidad que ofrecía Ziggy de “referenciar rutas de Laravel desde JavaScript”. Con el enfoque de importar y usar las funciones generadas, mejora enormemente la seguridad de tipos, el soporte de IDE y el tree-shaking. Incluso con la actual v0.1.x ya se logra la referencia type-safe de rutas y acciones de controlador, y se adopta por defecto en los starter kits de Laravel basados en Inertia. En la próxima versión en desarrollo en la rama next está previsto que evolucione a una base type-safe más amplia, generando también como TypeScript Form Requests, modelos Eloquent, Enums y page props de Inertia.

GitHub de Laravel Wayfinder

Código fuente, CHANGELOG e issues aquí.

Vite Plugin Wayfinder

Detalles de las opciones de configuración del plugin de Vite aquí.
Última modificación el 13 de julio de 2026