Skip to main content

What is Precognition

Precognition is a mechanism that runs server-side validation before a form is submitted. You can use your Laravel rules as-is on the frontend without redefining them. Unlike normal requests, Precognition requests execute a route’s middleware and form request validation, but not the controller method body itself. That makes it well-suited to real-time validation as the user types.

Installation

In Laravel 13, you don’t need to install the backend laravel/precognition package. What you do need is a frontend helper package.
  • Vue: laravel-precognition-vue
  • React: laravel-precognition-react
  • Alpine.js: laravel-precognition-alpine
npm install laravel-precognition-vue
npm install laravel-precognition-react
npm install laravel-precognition-alpine
Inertia has built-in Precognition support from 2.3, and it also works out of the box in Inertia 3. When using Inertia forms, you typically don’t need to add laravel-precognition-vue / laravel-precognition-react.

Backend configuration

Add the HandlePrecognitiveRequests middleware to your route. It’s practical to gather validation rules into a form request. Consolidating rules into a form request makes reuse and separation of concerns easier.
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
use Illuminate\Support\Facades\Route;

Route::post('/users', function (StoreUserRequest $request) {
    // Only executed on a real submission
})->middleware([HandlePrecognitiveRequests::class]);
If you have custom middleware with side effects, skip them during Precognition.
public function handle(Request $request, Closure $next): mixed
{
    if (! $request->isPrecognitive()) {
        Interaction::incrementFor($request->user());
    }

    return $next($request);
}

Frontend integration

Alpine.js (Blade)

<form x-data="{
    form: $form('post', '/users', { name: '', email: '' }),
}">
    @csrf
    <input x-model="form.name" @change="form.validate('name')" />
    <template x-if="form.invalid('name')">
        <div x-text="form.errors.name"></div>
    </template>
</form>

Vue (Inertia.js)

<script setup>
import { useForm } from 'laravel-precognition-vue';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});
</script>

<template>
    <input v-model="form.name" @change="form.validate('name')" />
    <div v-if="form.invalid('name')">{{ form.errors.name }}</div>
</template>

React (Inertia.js)

import { useForm } from 'laravel-precognition-react';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});

<input
    value={form.data.name}
    onChange={(e) => form.setData('name', e.target.value)}
    onBlur={() => form.validate('name')}
/>

Vanilla JS with Axios

The Precognition library uses Axios. To use your existing Axios instance, swap it in with client.use().
import Axios from 'axios';
import { client } from 'laravel-precognition-vue';

window.axios = Axios.create();
window.axios.defaults.headers.common['Authorization'] = authToken;

client.use(window.axios);

Controlling validation timing

Use validate() to validate individual inputs.
form.validate('email');
You can adjust the debounce time with setValidationTimeout().
form.setValidationTimeout(3000);
If you want to validate files every time, use validateFiles().
form.validateFiles();
You can validate array inputs using wildcards.
form.validate('users.*.email');

Form helper

useForm() handles submission and error state together.
  • validating: A validation request is in progress
  • processing: A submission is in progress
  • errors: A list of errors
  • valid('field') / invalid('field'): The field’s validation state
  • submit(): Perform a regular submission
const submit = () => form.submit()
    .then(() => form.reset());

Comparing regular requests and Precognition requests

The diagram below shows the difference between how regular and Precognition requests are handled.
Last modified on July 13, 2026