Skip to content

Prefetching

Prefetching allows the Inertia.js client to load pages in the background before the user navigates to them. This improves perceived performance by reducing the time users wait for pages to load.

When prefetching is enabled on a link, Inertia makes a background request to fetch the page data before the user clicks. The server responds normally, and the client caches the response for instant navigation.

Cross-Inertia automatically detects prefetch requests via the Purpose: prefetch header and handles them appropriately.

Use the prefetch prop on Link components:

import { Link } from '@inertiajs/react'
// Prefetch on hover (default behavior when prefetch is enabled)
<Link href="/users/1" prefetch>
View User
</Link>
// Prefetch on mount (when component renders)
<Link href="/dashboard" prefetch="mount">
Dashboard
</Link>
// Prefetch on hover with delay
<Link href="/settings" prefetch="hover">
Settings
</Link>
  • hover: Prefetch when the user hovers over the link (most common)
  • mount: Prefetch when the component mounts (for high-priority links)
  • click: Prefetch on mouse down (shortest delay before navigation)

Control how long prefetched data is cached:

import { Link } from '@inertiajs/react'
// Cache for 30 seconds
<Link href="/users" prefetch cacheFor="30s">
Users
</Link>
// Cache for 5 minutes
<Link href="/reports" prefetch cacheFor="5m">
Reports
</Link>
// Single-use (use once, then refetch)
<Link href="/notifications" prefetch cacheFor={0}>
Notifications
</Link>

Use router.prefetch() for more control:

import { router } from '@inertiajs/react'
// Prefetch a page
router.prefetch('/users/1')
// Prefetch with options
router.prefetch('/dashboard', {
method: 'get',
data: { filter: 'active' },
})
// Prefetch with cache configuration
router.prefetch('/users/1', {}, { cacheFor: '1m' })

Track prefetch status with usePrefetch():

import { usePrefetch } from '@inertiajs/react'
function UserLink({ userId }) {
const { isPrefetching, isPrefetched } = usePrefetch(`/users/${userId}`)
return (
<Link href={`/users/${userId}`} prefetch>
{isPrefetching && <Spinner />}
{isPrefetched && <CheckIcon />}
View User
</Link>
)
}

Cross-Inertia automatically handles prefetch requests. No special configuration is required.

Prefetch requests include the Purpose: prefetch header. Cross-Inertia detects this and:

  1. Processes the request normally (returns full page data)
  2. Logs prefetch requests distinctly for debugging
  3. Supports all features (partial reloads, deferred props, etc.)

Prefetch requests are logged separately:

→ Prefetch: Users/Show (props: ['user', 'posts'])
→ Inertia XHR: Users/Show (props: ['user', 'posts'])

Prefetch works with partial reloads:

// Prefetch only specific props
<Link
href="/users/1"
prefetch
only={['user', 'recentPosts']}
>
View User
</Link>

Prefetch respects deferred props - they’re still loaded after the initial render:

@app.get("/users/{user_id}")
async def show_user(user_id: int, inertia: InertiaDep):
return inertia.render("Users/Show", {
"user": get_user(user_id),
# These load after render, even on prefetched pages
"activity": defer(get_activity, user_id),
"recommendations": defer(get_recommendations, user_id),
})

Prefetch common navigation destinations:

import { Link } from '@inertiajs/react'
function Navigation() {
return (
<nav>
<Link href="/dashboard" prefetch="mount">
Dashboard
</Link>
<Link href="/users" prefetch="hover">
Users
</Link>
<Link href="/settings" prefetch="hover">
Settings
</Link>
</nav>
)
}

Prefetch detail pages on hover:

import { Link } from '@inertiajs/react'
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>
<Link
href={`/users/${user.id}`}
prefetch="hover"
cacheFor="1m"
>
{user.name}
</Link>
</li>
))}
</ul>
)
}

Prefetch tab content:

import { Link, usePage } from '@inertiajs/react'
function UserTabs({ userId }) {
const { url } = usePage()
return (
<div className="tabs">
<Link
href={`/users/${userId}`}
prefetch={url !== `/users/${userId}`}
>
Profile
</Link>
<Link
href={`/users/${userId}/posts`}
prefetch={url !== `/users/${userId}/posts`}
>
Posts
</Link>
<Link
href={`/users/${userId}/settings`}
prefetch={url !== `/users/${userId}/settings`}
>
Settings
</Link>
</div>
)
}

Flush specific cached pages:

import { router } from '@inertiajs/react'
// Flush specific URL from cache
router.flush('/users/1')
// Flush by cache tags
router.flushByCacheTags('user-1')

Use cache tags for grouped invalidation:

<Link
href={`/users/${userId}`}
prefetch
cacheTags={[`user-${userId}`, 'users']}
>
View User
</Link>
// Invalidate all user-related caches
router.flushByCacheTags('users')

Good candidates:

  • Navigation menu items
  • List item detail pages
  • Next/previous pagination links
  • Tabbed interface content

Avoid prefetching:

  • Pages with constantly changing data
  • Heavy pages that are rarely visited
  • Protected pages (may prefetch unnecessarily)

Choose cache duration based on data freshness needs:

// Static content - cache longer
<Link href="/about" prefetch cacheFor="1h">About</Link>
// Dynamic content - cache briefly
<Link href="/notifications" prefetch cacheFor="10s">Notifications</Link>
// Very dynamic - single use
<Link href="/live-feed" prefetch cacheFor={0}>Live Feed</Link>
  1. Start with hover prefetch - It’s the safest default
  2. Use mount sparingly - Only for high-priority, frequently accessed pages
  3. Set appropriate cache times - Balance freshness vs performance
  4. Combine with partial reloads - Prefetch only the data you need
  5. Monitor network usage - Prefetching increases requests