laravel/wayfinder
Laravel Wayfinder bridges your Laravel backend and TypeScript frontend by generating fully-typed, importable TypeScript functions for your controllers and routes—no more hardcoded URLs or manual syncing. Includes a Vite plugin that regenerates definitions automatically during builds and dev server r...
Architecture fit
Wayfinder is a build-time code generator, not a runtime library. A Laravel artisan command (wayfinder:generate) introspects the registered router and controller signatures and emits typed TypeScript modules into resources/js/{wayfinder,actions,routes}. The Vite plugin (@laravel/vite-plugin-wayfinder) wires generation into dev-server file watching and the production build. Architecturally this means: zero runtime dependency, zero production PHP footprint, and a hard build-time coupling between the Laravel app and the frontend build. It fits cleanly only where the Laravel backend and the TS frontend live in the same repository and the same build pipeline — the canonical Inertia monolith. It is a poor fit for a decoupled SPA/API or mobile client consuming a remote Laravel API, because generation requires booting the PHP app.
Integration feasibility
Install is two steps (composer require laravel/wayfinder, npm i -D @laravel/vite-plugin-wayfinder) plus a one-block vite.config.ts change. Output is conventional: named exports per controller method and per named route, each callable or exposing .url(), .get(), .head(), .form(), plus an options argument for query/mergeQuery. First-class Inertia interop (form.submit(store()), <Link href={show(1)}>) is the strongest adoption lever — it removes an entire class of hand-written URL strings. Cost is genuinely low: roughly a half-day spike plus CI wiring for a team already on Inertia.
Technical risk
php artisan route:clear before npm run build. Any pipeline that ends with php artisan optimize is latently broken until fixed.index["/clients/{client}/payments"](...)). Correct, but a sharp edge that surfaces only at the call site.int4 added in v0.1.9) imply parameter typing is inferred, not asserted — misclassification produces silent string | number widening or compile breaks.Key questions
route:cache/optimize ordering, and who owns changing it?delete, import), that would produce non-obvious generated output?strict mode, and does our typecheck step run after generation in CI?Stack fit
Ideal: Laravel 11/12+ with Inertia + React/Vue, TypeScript, Vite, single repo. Good: same, with Blade forms wanting --with-form for conventional submissions. Poor: separate SPA repo, Next.js/Remix frontends hitting an API, or any consumer without PHP in the build environment.
Migration path
Adopt incrementally rather than repo-wide. Pilot on one feature slice: enable the Vite plugin, run wayfinder:generate, and replace hand-written URL strings in that slice only. Compare generated output against existing constants/helpers. Only after the pilot passes a full deploy cycle should we consider replacing shared route helpers. Keep the generated directories out of version control (README explicitly supports .gitignore) so they cannot drift or be hand-edited.
Compatibility Confirm before committing: Laravel version floor, PHP version, Vite major version supported by the plugin, TypeScript version (v0.1.13 landed strict-mode query-param fixes, so pin a recent patch), and Inertia major version. Treat the plugin and the Composer package as a versioned pair — they evolve together and mismatches are the likeliest source of silent breakage.
Sequencing
php artisan route:clear before the frontend build step.route:clear → wayfinder:generate (or npm run build) → tsc --noEmit → tests. Typecheck must run after generation.Maintenance Low steady-state carrying cost — generated code is disposable and fully regenerated each build. The real maintenance surface is the toolchain pair (Composer package + Vite plugin) and the pre-1.0 churn. Budget for periodic upgrade-and-diff reviews rather than continuous work. Because output is gitignored, there is no merge-conflict tax, but also no reviewable record of what changed — pair upgrades with a snapshot diff in CI to make regeneration drift visible.
Support No first-party commercial support; MIT-licensed, community-maintained under the Laravel org. Debugging falls to us. Mitigation: keep the pilot's generated output as a reference fixture and document the failure signatures so on-call engineers recognize them fast.
Scaling
Generation is roughly linear in route count; expect sub-10s for typical apps and a manageable hit for very large route tables — measure during the spike. Bundle size is the more real concern: importing individual named functions tree-shakes well, importing a whole controller (PostController.show(1)) prevents tree-shaking and pulls in every action in that controller. Codify a lint/import convention preferring named-function and named-route imports.
Failure modes
string | number, weakening the guarantee Wayfinder exists to provide.deleteMethod/importMethod mismatch expectations; low impact, caught at typecheck.Ramp-up Low for Laravel/Inertia engineers — a half-day to competency, since the mental model is thin (import and call). Medium for frontend-only engineers who will not intuit that these modules are PHP-derived and regenerated, and for platform/DevOps engineers who own the build ordering change. The one concept that must be taught explicitly is the dictionary-export fallback for multi-route actions, because it is the only place the otherwise-uniform API changes shape.
How can I help you explore Laravel packages today?