Laravel Daily's

Graceful Data Loading in Inertia 3.x: Rescue Slots & Deferred Props in Laravel + Vue SPAs

hero image

Building modern single-page applications demands speed and resilience. Users expect instant initial page loads without sacrificing rich data. Slow queries or unstable networks can break entire views.

Inertia 3.x solves this friction. By combining server-side deferred props with client-side rescue slots, you keep your php web framework fast and your Vue interfaces fault-tolerant.

Let us dive into the defer-and-rescue pattern.

The Problem with Traditional SPA Loading

Traditional SPAs fetch all route data before rendering. If one heavy database query stalls, your user stares at a blank screen.

As a developer using professional php developer tools, you want cleaner solutions. You want the critical shell of your page to render immediately. Heavy widgets or paginated lists can load asynchronously afterward.

Inertia 3.x introduces Inertia::defer() for precisely this workflow.

Laravel Controller Deferral

Defining Deferred Props in Laravel

On the backend, you mark non-critical data as deferred inside your controller. This tells the framework to send the initial page response right away, dispatching a secondary background request for the deferred payload.

Here is how you structure your controller:

use Inertia\Inertia;
use App\Models\User;
use Illuminate\Http\Request;

public function index(Request $request)
{
    return Inertia::render('Users/Index', [
        'filters' => $request->only('search'),
        'users' => Inertia::defer(fn () => User::latest()->paginate(15)),
    ]);
}

The users prop is now deferred. The initial HTML response arrives instantly, while Inertia fetches the user collection in a follow-up request.

Consuming Deferred Data in Vue 3

On the frontend, you import the <Deferred> component from @inertiajs/vue3. You wrap any template section that relies on your deferred data.

<script setup>
import { Deferred } from '@inertiajs/vue3'

defineProps({
  users: Object,
})
</script>

<template>
  <Deferred :data="users">
    <template #fallback>
      <div class="p-4 text-gray-500">
        Loading users...
      </div>
    </template>

    <template #default="{ data, reloading }">
      <div class="space-y-2">
        <div v-if="reloading" class="text-xs text-gray-400">
          Refreshing users...
        </div>

        <ul class="divide-y divide-gray-200">
          <li v-for="user in data.data" :key="user.id" class="py-2">
            {{ user.name }} ({{ user.email }})
          </li>
        </ul>
      </div>
    </template>
  </Deferred>
</template>

The #fallback slot displays while the deferred payload loads for the first time. Once resolved, the #default slot renders your clean data list.

Vue Rescue Slots

Graceful Error Handling with Rescue Slots

Network drops and server exceptions happen. When a deferred prop fails to load, standard applications often break silently or leave users stranded. Inertia 3.x introduces the #rescue slot to catch these failures gracefully.

You define a dedicated error state right inside your component markup:

<template>
  <Deferred :data="users">
    <template #fallback>
      <div class="p-4 text-gray-500">Loading users...</div>
    </template>

    <template #rescue="{ reloading }">
      <div class="p-4 text-red-600 space-x-2">
        <span>Failed to load user records.</span>
        <button
          class="px-3 py-1 border rounded"
          :disabled="reloading"
          @click="retryUsers"
        >
          <span v-if="!reloading">Retry</span>
          <span v-else>Retrying...</span>
        </button>
      </div>
    </template>

    <template #default="{ data, reloading }">
      <!-- render valid data -->
    </template>
  </Deferred>
</template>

If the server throws an exception or returns a non-2xx status for that specific deferred prop, Inertia switches the component into rescue mode. Your custom fallback UI displays immediately without breaking the surrounding layout.

Deferred Loading and Retry Pattern

Retrying Failed Requests

Once your component enters the rescue state, it remains there until you explicitly trigger a reload. You use Inertia's router utility to re-request only the failed prop.

Here is the complete retry method setup:

<script setup>
import { Deferred, router } from '@inertiajs/vue3'

defineProps({
  users: Object,
})

function retryUsers() {
  router.reload({
    only: ['users'],
    preserveScroll: true,
  })
}
</script>

This partial reload fetches only the users prop from the server. The reloading boolean passed into your rescue slot automatically updates, allowing you to disable buttons or show loading spinners while the retry executes.

Building Robust SPAs

Whether you build a SaaS dashboard or build rest api with php endpoints for complex single-page apps, data resilience matters. Inertia 3.x bridges the gap between server-driven routing and reactive client interfaces.

Explore the official Laravel documentation to see how clean architecture and modern developer tools accelerate your workflow. Give deferred props and rescue slots a try in your next project, and let us know how you build resilient interfaces.

Previous
Building Smarter Agents: Laravel AI SDK's Deferred Tool Discovery and Tool Choice Control