Seamless Frontend Experience with Laravel Precognition

· 4 min read

One of the biggest pain points in full-stack application development is the duplication of validation logic.

You write validation rules in Laravel's Form Request to protect the backend. But for a good UX (users see errors as they type), you often have to rewrite those rules in JavaScript on the frontend (using VeeValidate, Zod, or Yup...).

This leads to:

  1. Code duplication: Change a rule, update it in two places.
  2. Inconsistency: PHP's email regex might differ slightly from JS.
  3. Security risks: Forgetting to update the backend after changing the frontend.

Laravel Precognition solves this problem. It allows the frontend to ask the backend: "If I were to submit this data, would it be valid?" without actually executing the controller logic.

How Precognition Works

Basically, Precognition intercepts the request using a special middleware.

  1. Frontend sends a request (e.g., POST /users) with the header Precognition: true.
  2. Laravel middleware detects this header.
  3. Laravel runs the Validation process (Form Request).
  4. If Validation Fails -> Returns 422 error as usual.
  5. If Validation Passes -> Stops immediately, does not run the Controller, returns 204 No Content.

This is extremely fast and lightweight because it skips all the heavy processing logic in the Controller (DB insert, sending mail, queuing jobs...).

Installation and Usage

1. Backend Preparation

In Laravel 10+, Precognition is built-in. You just need to ensure the HandlePrecognitiveRequests middleware is registered (usually default in app/Http/Kernel.php or bootstrap/app.php in newer versions).

Suppose you have a UserStoreRequest:

// app/Http/Requests/UserStoreRequest.php
public function rules(): array
{
    return [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'email', 'unique:users,email'],
        'password' => ['required', 'min:8', 'confirmed'],
    ];
}

Your Controller needs no changes:

public function store(UserStoreRequest $request) 
{
    // This logic will NOT run when the request is precognitive
    User::create($request->validated());
}

2. Frontend Integration (Vue 3 Example)

Laravel provides libraries for popular frameworks.

npm install laravel-precognition-vue

Use useForm from Precognition instead of Inertia or regular refs:

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

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

const submit = () => form.submit({
    preserveScroll: true,
    onSuccess: () => form.reset(),
});
</script>

<template>
    <form @submit.prevent="submit">
        <div>
            <label>Name</label>
            <!-- validate('name') will call API to check on blur or change -->
            <input 
                v-model="form.name" 
                @change="form.validate('name')"
            />
            <div v-if="form.invalid('name')" class="error">
                {{ form.errors.name }}
            </div>
        </div>

        <!-- Similar for Email, Password... -->
        
        <button :disabled="form.processing">Create User</button>
    </form>
</template>

3. Customizing Rules During Precognition

Sometimes you have "heavy" rules (e.g., checking uniqueness in a large database table) that you don't want to run every time user types a character.

You can use the isPrecognitive() method of the Request to adjust:

public function rules(): array
{
    return [
        'avatar' => [
            ...
            // Only validate image dimensions on actual submit
            !$this->isPrecognitive() ? Rule::dimensions()->maxWidth(1000) : null, 
        ],
        // ...
    ];
}

Side Effects (Beware!)

Since Precognition runs Validation, if you have "side effect" logic (like creating files, logging activity) in your prepareForValidation method or Custom Rules, they might be executed multiple times.

Golden Rule: Validation should only be Validation. Do not change system state within the Validation layer.

Conclusion

Laravel Precognition is an excellent bridge between the smooth UX of Client-side validation and the reliability and security of Server-side validation. It completely eliminates logic duplication, keeping your codebase DRY (Don't Repeat Yourself) than ever.

If you are building an Inertia.js project or SPA with Laravel API, this is a "must-have" feature.

Comments