Laravel Daily's

Graceful Data Loading: Using Deferred Props with Rescue Slots in Inertia 3.x

hero image

Modern web applications often face a performance bottleneck. Slow database queries or external API calls can delay the entire page response. Users end up staring at a blank screen while the server waits for data.

Inertia 3.x introduces a powerful solution to this problem. Deferred props allow you to ship the initial page layout instantly. The heavy data follows in a background request. This improves the perceived speed of your php web framework applications significantly.

Deferred Props: The Server-Side Setup

You define deferred props directly in your Laravel controllers. Instead of passing a finished collection, you pass a closure to Inertia::defer. This tells the framework to resolve the data after the initial request.

use Inertia\Inertia;

public function index()
{
    return Inertia::render('Dashboard', [
        'stats' => Inertia::defer(fn () => Performance::getSlowStats()),
        'teams' => Inertia::defer(fn () => Team::all(), rescue: true),
    ]);
}

The rescue: true flag is a critical addition. It ensures that if the closure fails, the whole page doesn't crash. Instead, the prop enters a rescued state that the frontend can handle gracefully. This is one of the most useful php developer tools for building resilient systems.

The Vue <Deferred> Component

On the frontend, you manage these props using the new <Deferred> component. This component acts as a wrapper for your data. It provides specific slots for different states of the loading process.

Dashboard interface built with Laravel and Vue

The primary slot renders once the data arrives. You use the data attribute to specify which prop to watch. This matches the key you defined in your Laravel controller.

<template>
  <Deferred data="stats">
    <template #fallback>
      <div class="skeleton-loader">Loading stats...</div>
    </template>

    <div v-if="stats">
      <h3>{{ stats.total_revenue }}</h3>
    </div>
  </Deferred>
</template>

The fallback slot displays immediately while the background request is active. This prevents the "blank page" effect during slow data fetches. It keeps the user engaged with a skeleton UI or a loading spinner.

Rescue Slots: Handling Failures Gracefully

Network requests fail and external APIs go down. Handling these errors usually requires complex state management. Inertia 3.x simplifies this with the rescue slot.

Robot fixing a broken data pipeline

If you enabled rescue: true on the server, the component will switch to the rescue slot if the fetch fails. This allows you to show a friendly error message. You can even include a "Retry" button that triggers a partial reload.

<template>
  <Deferred data="teams">
    <template #rescue="{ reloading }">
      <div class="error-box">
        <p>Could not load teams.</p>
        <button @click="$inertia.reload({ only: ['teams'] })" :disabled="reloading">
          {{ reloading ? 'Retrying...' : 'Retry' }}
        </button>
      </div>
    </template>

    <TeamList :teams="teams" />
  </Deferred>
</template>

The reloading boolean provided to the slot is essential. It lets you know if a manual refresh is currently in progress. You can use it to disable buttons or show a secondary spinner within the error state.

Keeping Data Fresh with usePoll

Deferred data is often dynamic, such as live stats or user lists. Once the initial deferral finishes, you might want to keep that data updated. The usePoll hook makes this straightforward.

Digital dashboard with refreshing progress bars

You can configure polling to refresh specific props at regular intervals. This works perfectly with deferred props. The initial load happens in the background, and subsequent updates keep the UI current.

import { usePoll } from '@inertiajs/vue3'

usePoll(5000, {
  only: ['stats'],
})

This setup ensures your dashboard remains accurate without requiring full page refreshes. It mimics the behavior of a real-time app while maintaining the simplicity of a server-side framework. This approach is highly effective when you build rest api with php endpoints for internal dashboard use.

SSR and Hydration Nuances

Deferred props behave differently during Server-Side Rendering (SSR). When a page is rendered on the server, deferred props are skipped. The server generates the HTML containing the fallback slot content.

Once the page reaches the browser, Inertia hydrations kicks in. The client-side router notices the missing deferred data. It immediately triggers the background request to fetch those props.

This mechanism ensures a fast First Contentful Paint. Search engines and users see the main layout immediately. The heavier components populate as soon as the data is ready. It balances the benefits of SSR with the flexibility of modern client-side loading.

Pattern: The Complex Dashboard

Consider a dashboard managing teams, users, and permissions. Fetching all three in a single request might take several seconds. Using the patterns above, you can load them independently.

You might load the current user synchronously to show the navigation. Then, defer the teams and permissions.

return Inertia::render('Admin/Dashboard', [
    'user' => auth()->user(),
    'teams' => Inertia::defer(fn () => Team::all(), rescue: true),
    'permissions' => Inertia::defer(fn () => $user->getAllPermissions()),
]);

In your Vue component, use multiple <Deferred> blocks. This allows the teams to show up as soon as they are ready. Even if the permissions check takes longer, it won't block the team list from appearing.

Forward-Looking Development

Inertia 3.x continues to bridge the gap between traditional server-side rendering and single-page applications. These features reduce the friction of handling asynchronous data. They allow developers to focus on building features rather than managing loading states.

We are excited to see how the community applies these tools. If you are exploring the latest updates, check out the Laravel April product updates for more context. Your feedback helps shape the future of the ecosystem.

We'd love to hear how you are using rescue slots in your production apps. Reach out to the community and share your implementation patterns.

Previous
Why the Laravel AI SDK Will Change the Way You Use an MVC Framework PHP
Next
Laravel Trends 2026: AI-First Framework, Livewire 4, and the Evolution of PHP Development