Wayfinder + Precognition catch up with Laravel's QUERY routes

Wayfinder 0.1.22 and Precognition 2.1.1 add first-class QUERY support, so Route::query() finally works end-to-end with typed clients and live validation.

For your AI agent

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

Read https://laravel-vuejs.space/wayfinder-precognition-query-method.md
Wayfinder 0.1.22 and Precognition 2.1.1 add first-class QUERY support, so Route::query() finally works end-to-end with typed clients and live validation.
Show the diff. Do not commit.
On this page · 10 sections
  1. What’s new at a glance
  2. Why QUERY again (one paragraph)
  3. Wayfinder: typed .query() and form spoofing
  4. Call it with fetch (Inertia does not speak QUERY yet)
  5. Precognition: client.query() for live validation
  6. Optional peer fix (#176)
  7. Shared URI, middleware aliases, barrel import
  8. Upgrade notes
  9. Recap
  10. FAQ
  11. Next steps
  12. Sources

Laravel 13.35 gave you Route::query(). Your routes file was ready. Your TypeScript client was not. Wayfinder 0.1.22 and Precognition 2.1.1 close that gap: typed .query() helpers, form spoofing, and live validation with a body.

TL;DR

  • Wayfinder 0.1.22 (15 Oct 2026) adds "query" to the Method union, so RouteDefinition<"query"> type-checks and you get search.query() plus search.form.query().
  • Precognition 2.1.1 (tag, same day) adds client.query(url, data): data goes in the body (like POST), and CSRF still applies.
  • HTML forms only speak GET/POST, so Wayfinder spoofs QUERY as POST with ?_method=QUERY, same pattern as PUT/PATCH/DELETE.
  • Bonus: shared-URI routes are now keyed by verb (#303), middleware aliases resolve for URL defaults (#295), and a barrel self-import bug is fixed (#317).

What you'll learn

  • search.query() from Wayfinder 0.1.22
  • client.query() / Precognition live validation with a body
  • Form spoofing via _method=QUERY
  • Shared-URI routes keyed by verb (#303)

Who it's for: Laravel 13 + Vue / Inertia apps using Wayfinder or Precognition

Applies to: laravel/wayfinder v0.1.22 · laravel-precognition@2.1.1 · Laravel 13.35+

What’s new at a glance#

PieceVersionWhat you get
laravel/wayfinderv0.1.22"query" on Method, .query(), form spoofing (#324)
laravel-precognitionv2.1.1 (npm + git tag)client.query() with body + CSRF (#179)
laravel/frameworkv13.35+Route::query() (#61797) — already covered

If you already ship Route::query() from Laravel 13.35, this is the front-end half of that story.

Why QUERY again (one paragraph)#

QUERY is a safe, idempotent method with a request body — think “GET with JSON filters”. Laravel registered it in 13.35; Wayfinder and Precognition now speak it without casting everything to POST.

Wayfinder: typed .query() and form spoofing#

Before 0.1.22, a route registered with Route::match(['QUERY'], …) already generated a URL, but the Method type in wayfinder.ts stopped at "options". RouteDefinition<"query"> failed to type-check. #324 adds "query" to that union.

routes/web.phpphp
use App\Http\Controllers\SearchController;

Route::query('/search', [SearchController::class, 'index'])
    ->name('search.index');

Route::match(['GET', 'QUERY'], '/search/{type}', [SearchController::class, 'show'])
    ->name('search.show');

After php artisan wayfinder:generate:

resources/js/pages/Search.vue (script setup)typescript
import { search } from '@/routes'

// QUERY-only route
search.index()        // { url: '/search', method: 'query' }
search.index.query()  // same

// GET + QUERY route: default stays GET; pick QUERY explicitly
search.show('posts')        // { url: '/search/posts', method: 'get' }
search.show.query('posts')  // { url: '/search/posts', method: 'query' }

HTML forms cannot send QUERY. Wayfinder spoofs it the same way it spoofs PUT:

typescript
search.index.form()
// { action: '/search?_method=QUERY', method: 'post' }

search.show.form.query('posts')
// { action: '/search/posts?_method=QUERY', method: 'post' }

Symfony’s Request allows overriding the method to QUERY (it only blocks GET, HEAD, CONNECT and TRACE), so Laravel’s method spoofing middleware accepts it.

Heads up: lowercase method string

Generated definitions use lowercase "query", consistent with "patch". The Fetch standard does not normalise that casing, so if you pass the method straight to fetch(), uppercase it yourself ('QUERY') when your HTTP client is picky.

Call it with fetch (Inertia does not speak QUERY yet)#

Inertia’s Method type is still get | post | put | patch | delete as of 3.9.1, so router.visit({ method: 'query' }) will not type-check. Use Wayfinder’s definition with fetch (or axios), and keep CSRF in mind for web routes:

resources/js/pages/ProductSearch.vuetypescript
import { search } from '@/routes'

async function runSearch(filters: Record<string, unknown>) {
  const def = search.index.query() // { url: '/search', method: 'query' }
  const res = await fetch(def.url, {
    method: 'QUERY', // uppercase for picky clients / Fetch
    headers: {
      'Content-Type': 'application/json',
      'X-XSRF-TOKEN': decodeURIComponent(
        document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
      ),
      Accept: 'application/json',
    },
    credentials: 'same-origin',
    body: JSON.stringify(filters),
  })
  return res.json()
}

When Inertia adds QUERY, you will be able to pass the Wayfinder object straight through. Until then, Precognition (next section) is the polished path for live validation against a QUERY route.

Precognition: client.query() for live validation#

Precognition 2.1.1 adds a query method next to post / put / patch. Like those, data goes in the request body, not as query-string params. GET and DELETE still merge into params.

resources/js/pages/ProductSearch.vuetypescript
import { useForm } from 'laravel-precognition-vue'
import { search } from '@/routes'

const form = useForm('query', search.index.url(), {
  q: '',
  category: null as string | null,
  price_min: null as number | null,
  price_max: null as number | null,
  tags: [] as string[],
})

// On each field change, Precognition hits the QUERY route with a JSON body
form.validate('q')

Under the hood that is client.query(url, data) → mergeConfig('query', …) → body merge (not params). The Precognition suite asserts config.method === 'query' and that data is present.

Gotcha: QUERY is still CSRF-verified

Laravel’s QUERY support (#61797) deliberately does not treat QUERY as a “reading” method for CSRF. The handler carries a body; verifying the token keeps CSRF independent of your CORS config. Precognition already sends the XSRF header on body-carrying methods — including query. Opt out per route with preventRequestForgery(except: […]) only if you know why.

Optional peer fix (#176)#

Same tag also fixes the axios adapter to use the default export, so the optional axios peer can be absent when you use the fetch client. If you saw odd import errors after dropping axios, bump to 2.1.1.

Shared URI, middleware aliases, barrel import#

Three more Wayfinder fixes in 0.1.22 worth knowing:

PRProblemFix
#303Two verbs on the same URI / invokable controller wrote the same dictionary key twiceEntries keyed by verb + URI when the URI is shared
#295Middleware aliases never resolved during wayfinder:generate, so URL::defaults() from those middleware were missedKernel is resolved before walking routes
#317A barrel child named index imported ./index and pulled itself inImport by full path; drop only leaf-only index children

The shared-URI fix is the one you feel when you have:

php
Route::post('/actions/{name}', ActionController::class)->name('actions.run');
Route::get('/actions/{name}', ActionController::class)->name('actions.show');

Before #303 the generated action file did not compile. After it, you get distinct keys (post /actions/{name} vs get /actions/{name}) and you still pick the route explicitly.

Flow: Vue calls search.query() or Precognition client.query() with a JSON body, Laravel matches Route::query(), CSRF is verified, then the controller returns search results.
QUERY end-to-end: typed client → body + CSRF → Route::query()

Upgrade notes#

  1. Framework first. You need Laravel 13.35+ for Route::query(). See the 13.35 post if you skipped it.
  2. Wayfinder. composer update laravel/wayfinder to ^0.1.22, then php artisan wayfinder:generate.
  3. Precognition. Bump the npm packages you use:
    bash
    npm install laravel-precognition@2.1.1 laravel-precognition-vue@2.1.1
    # or -react / -alpine / core, matching your stack
  4. Smoke-test one route. Register a QUERY search route, hit it from Wayfinder .query() and from a Precognition useForm('query', …), confirm 204/200 and that a missing CSRF token still 419s.

No breaking changes in either package for existing GET/POST routes. Adopting QUERY on a route is opt-in.

Generate and inspect a QUERY definition

bash
# After adding Route::query('/search', ...) and updating Wayfinder:
php artisan wayfinder:generate
rg -n "method: .query.|\"query\"" resources/js/routes resources/js/actions | head

Recap#

  • Laravel had Route::query() since 13.35; Wayfinder 0.1.22 and Precognition 2.1.1 make it usable from TypeScript.
  • Wayfinder: search.query(), search.form.query() with _method=QUERY spoofing.
  • Precognition: client.query(url, data) sends a body and keeps CSRF.
  • Also in Wayfinder 0.1.22: shared-URI-by-verb keys, middleware-alias URL defaults, barrel self-import fix.

FAQ#

Do I need both Wayfinder and Precognition?

No. Use Wayfinder for typed route helpers, Precognition for live validation, or both together. Each release independently adds QUERY.

Does Inertia support QUERY visits yet?

Not in 3.9.1 — its Method union is still get/post/put/patch/delete. Use fetch/axios with Wayfinder's definition, or Precognition useForm('query', …) for live validation. Inertia pages can still render the response once you have the data.

Why does my HTML form POST to `/search?_method=QUERY`?

Browsers only submit GET and POST. Wayfinder's .form.query() spoofs QUERY the same way Laravel spoofs PUT/PATCH/DELETE.

Is QUERY CSRF-exempt like GET?

No. Laravel deliberately keeps CSRF on QUERY (#61797). Precognition sends the XSRF header; bare fetch must too.

Was there a GitHub Release for Precognition 2.1.1?

Not at publish time — only a git tag and npm publish (same pattern as 2.1.0). Trust the tag v2.1.1 and the npm version.

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.