| name | wayfinder-development |
| description | Activates whenever working with Wayfinder-generated TypeScript — routes, models, enums, form requests, Inertia page props, shared data, broadcast channels/events, or environment variables. Use when importing from @/wayfinder/, syncing Laravel types to TypeScript, or keeping frontend and backend perfectly in sync. |
| license | MIT |
| metadata | {"author":"laravel"} |
Wayfinder Development (Beta / next)
Documentation
Use search-docs for detailed Wayfinder patterns and documentation.
Overview
Wayfinder (beta) bridges your Laravel backend and TypeScript frontend by auto-generating fully-typed TypeScript from your Laravel code. All output lives under resources/js/wayfinder (alias @/wayfinder).
Wayfinder generates TypeScript for:
- Routes & Controller Actions — type-safe URL functions with parameter validation
- Named Routes — access routes via Laravel route names
- Form Requests — TypeScript types from validation rules
- Eloquent Models — TypeScript interfaces with attributes and relationships
- PHP Enums — TypeScript types and runtime constants
- Inertia Page Props — types for Inertia page data
- Inertia Shared Data — types for HandleInertiaRequests shared data
- Broadcast Channels — type-safe channel name builders
- Broadcast Events — typed WebSocket event payloads
- Environment Variables — typed
import.meta.env for VITE_* vars
Quick Reference
Generate
Run after any PHP changes if the Vite plugin isn't running:
php artisan wayfinder:generate --no-interaction
--with-form, --skip-actions, --skip-routes flags are removed in the beta — configure via config/wayfinder.php instead.
Routes & Controller Actions
import { PostController } from '@/wayfinder/App/Http/Controllers/PostController'
PostController.index()
PostController.show({ post: 1 })
PostController.show.url({ post: 42 })
PostController.index.get()
PostController.update.patch({ post: 1 })
PostController.destroy.delete({ post: 1 })
PostController.update.form({ post: 1 })
PostController.index({ query: { page: 2 } })
PostController.index({ mergeQuery: { page: 3, sort: null } })
Named Routes
import posts from '@/wayfinder/routes/posts'
posts.index()
posts.show({ post: 1 })
Enums
import PostStatus from '@/wayfinder/App/Enums/PostStatus'
PostStatus.Published
if (post.status === PostStatus.Draft) { ... }
import { App } from '@/wayfinder/types'
function setStatus(status: App.Enums.PostStatus) { ... }
Models
import { App } from '@/wayfinder/types'
function displayUser(user: App.Models.User) {
console.log(user.name, user.email)
}
Form Request Types
import { App } from '@/wayfinder/types'
const form = useForm<App.Http.Controllers.PostController.Store.Request>()
Inertia Page Props
<script setup lang="ts">
import { Inertia } from "@/wayfinder/types";
defineProps<Inertia.Pages.Dashboard>();
// Inertia.Pages.Dashboard extends Inertia.SharedData automatically
</script>
Broadcast Channels & Events
import { BroadcastChannels } from '@/wayfinder/broadcast-channels'
import { App } from '@/wayfinder/types'
Echo.private(BroadcastChannels.orders(orderId)).listen('OrderShipped', (e) => {
console.log(e.trackingNumber)
})
Environment Variables
Wayfinder generates vite-env.d.ts — VITE_* vars in .env become typed on import.meta.env:
const appName = import.meta.env.VITE_APP_NAME
Wayfinder + Inertia
Use .form() with the <Form> component:
<Form v-bind="PostController.store.form()"><input name="title" /></Form>
Or with useForm:
form.submit(PostController.store())
Verification
- Run
php artisan wayfinder:generate to regenerate if Vite plugin isn't running
- Check TypeScript imports resolve under
@/wayfinder/
- Verify
types.d.ts contains expected model, enum, and Inertia namespaces
Breaking Changes from Previous Beta
- Import path changed:
@/actions/ and @/routes/ → @/wayfinder/
- Controller imports are now namespace objects:
PostController.show() not { show }
types.ts renamed to types.d.ts
--with-form, --skip-actions, --skip-routes CLI flags removed — use config/wayfinder.php
- Vite plugin: remove
routes, actions, and withForm arguments
Common Pitfalls
- Using old
@/actions/ or @/routes/ import paths instead of @/wayfinder/
- Forgetting to regenerate after PHP model, enum, or route changes
- Using CLI flags that no longer exist (
--with-form, --skip-actions)
- Not using type-safe parameter objects for route model binding