Typed Laravel routes in Vue with Wayfinder

Wayfinder writes a TypeScript function per controller action. The Inertia form takes that function. You do not add a second router.

For your AI agent

Copies a prompt. Paste it into the AI agent you already have open.

Read https://laravel-vuejs.space/laravel-wayfinder-vue.md
Wayfinder writes a TypeScript function per controller action. The Inertia form takes that function. You do not add a second router.
Do not install that package beside these generated functions.
Show the diff. Do not commit.

Next: Laravel Sail with Vue and Vite

On this page · 7 sections
  1. Generate
  2. The form
  3. Where this stops
  4. Recap
  5. FAQ
  6. Next steps
  7. Sources

You rename a route, every form that posted to the old string breaks, and nothing tells you until a user clicks. Wayfinder turns Laravel routes into TypeScript functions, so the build fails instead. Here is how the kit uses it.

TL;DR

  • The starter kit already ships Wayfinder; npm run dev regenerates files as routes change.
  • Import store from @/actions/App/Http/Controllers/PostController and pass :action="store()". No method needed.
  • store.url() is just a string, so a string href is a GET.
  • Clear a stale route:cache before wayfinder:generate on deploy.

What you'll learn

  • How Wayfinder generates actions from your routes
  • How to post a form to store()
  • What breaks on deploy and how to avoid it

Who it's for: Laravel + Vue developers on the starter kit

Applies to: Laravel 13 · Wayfinder · Inertia 3 · Vue 3 · TypeScript

The Vue starter kit already ships Wayfinder. It reads the Laravel routes and writes TypeScript functions for the controller actions. A form then posts to store() instead of a string you can typo. This is not Vue Router. Inertia still navigates. Adding a client router beside it is the mistake the stack guide warns about.

Typed props on the page are a separate job: TypeScript props.

Generate#

The Vite plugin in the kit regenerates the files while npm run dev is running. After you add a controller, run the command yourself if the import is missing.

bash
php artisan wayfinder:generate

Gotcha: stale route cache on deploy

The files land in resources/js/wayfinder, resources/js/actions, and resources/js/routes. You can gitignore all three. They are rebuilt. On deploy, generate against the routes you are shipping. A stale route:cache from the previous release makes Wayfinder skip new routes, and Vite then fails looking for a file that was never written. Clear that cache before generating. The rest of the build is the deploy guide.

The form#

A string you can typo, then A generated, typed action:

resources/js/pages/posts/Create.vuevue
<Form action="/posts" method="post">
resources/js/pages/posts/Create.vuevue
<Form :action="store()">

Import store from the file Wayfinder wrote for PostController. With the kit’s @ alias pointing at resources/js, that path is the one below. If your generate path differs, import the file that is actually on disk.

resources/js/pages/posts/Create.vuevue
<script setup lang="ts">
import { Form } from "@inertiajs/vue3";
import { store } from "@/actions/App/Http/Controllers/PostController";
</script>

<template>
  <Form :action="store()">
    <input name="title" />
    <input name="excerpt" />
    <button type="submit">Save</button>
  </Form>
</template>

Inertia reads the URL and the HTTP method from the Wayfinder object. You do not also pass method="post" unless you are posting to a plain string, which is what the CRUD guide does before this page. store() with no arguments matches POST /posts. An update action that needs the id is update(post.id) from the same generated module. Use the function the generator named after the controller method.

Heads up: store() vs store.url()

A <Link> infers the method from that same object: :href="store()". store() is a POST, so the link is a POST. store.url() is only the URL string, and a string href is a GET. Check the generated file before you invent a helper. The generator is the API. This page does not describe a second one.

Watch the build catch a rename

Rename store to save in PostController and its route, then run php artisan wayfinder:generate and npx vue-tsc --noEmit. The old import now fails type-checking instead of failing in the browser.

Where this stops#

Wayfinder does not validate the body. The form request from Precognition still does. It does not know which user may call update. That is a policy. A tutorial that says route() and Ziggy is the Ziggy map. Do not install that package beside these generated functions.

Recap#

  • Wayfinder writes one TypeScript function per controller action.
  • Pass the function to <Form> or <Link>; Inertia reads URL and method.
  • Regenerate after new routes; clear route:cache first on deploy.
  • Validation and authorization still live in Laravel.

FAQ#

Does the Laravel Vue starter kit use Ziggy or Wayfinder?

Wayfinder. It generates typed functions per controller action; Ziggy is not installed.

Why is my Wayfinder import missing?

The file was not generated yet. Run php artisan wayfinder:generate, and on deploy clear a stale route:cache first.

Should I commit the Wayfinder generated files?

You can gitignore resources/js/wayfinder, resources/js/actions and resources/js/routes; they are rebuilt.

Next steps#

Sources#

Found this useful?

Ask questions, share what you built.

Join thousands of Laravel and Vue developers in our Facebook group, or get new posts in your Telegram feed. Sharing this article helps too.

Keep reading

Newsletter

Get the best of Laravel & Vue, once a month.

One short email with new guides, release notes worth reading and hand-picked community links. No spam, unsubscribe any time.