Partial Reloads

Optimize performance by reloading only specific props.

See also

Official Inertia.js docs: Partial Reloads

What Are Partial Reloads?

Partial reloads let you request only specific props instead of the entire page data. This reduces payload size and server processing.

Lazy Props

Use lazy() to mark props that should only load during partial reloads:

from typing import Any

from litestar import get
from litestar_vite.inertia import lazy

@get("/dashboard", component="Dashboard")
async def dashboard() -> dict[str, Any]:
    return {
        "stats": get_stats(),                    # Always included
        "notifications": lazy("notifications", get_notifications),  # Partial only
        "activity": lazy("activity", get_activity_feed),            # Partial only
    }

Lazy props are excluded from the initial page load and only sent when explicitly requested via partial reload.

Static vs Callable Lazy Props

Static value - computed eagerly, sent lazily:

# Value computed now, but only sent during partial reload
lazy("count", len(expensive_query()))

Callable - computed and sent lazily:

# Function only called during partial reload
lazy("count", lambda: len(expensive_query()))
lazy("data", expensive_async_function)  # Async works too

Warning

Avoid the “False Lazy” pitfall:

# WRONG - function called immediately!
lazy("data", get_expensive_data())

# CORRECT - function reference passed
lazy("data", get_expensive_data)

Once Props

Use once() to cache props client-side after the first response:

from typing import Any

from litestar import get
from litestar_vite.inertia import once

@get("/settings", component="Settings")
async def settings() -> dict[str, Any]:
    return {
        "preferences": once("preferences", get_preferences),
        "feature_flags": once("feature_flags", get_feature_flags),
    }

Once props are included in initial loads, but the client caches their values and reuses them on subsequent visits.

Optional Props (WhenVisible)

Optional props are only included when explicitly requested:

from typing import Any

from litestar import get
from litestar_vite.inertia import optional

@get("/posts/{post_id}", component="Posts/Show")
async def show_post(post_id: int) -> dict[str, Any]:
    return {
        "post": await Post.get(post_id),
        "comments": optional("comments", lambda: Comment.for_post(post_id)),
    }

These work well with the WhenVisible component to load data as it enters the viewport.

Always Props

Use always() for data that must be included in every response, even when partial reloads filter props:

from typing import Any

from litestar import get
from litestar.request import Request
from litestar_vite.inertia import always, lazy

@get("/dashboard", component="Dashboard")
async def dashboard(request: Request) -> dict[str, Any]:
    return {
        "auth": always("auth", {"user": request.user}),
        "stats": lazy("stats", get_stats),
    }

Prop Type Comparison

Type

Initial Load

Partial Reloads

Typical Use

lazy()

Excluded

Included when requested

Heavy data on demand

optional()

Excluded

Only when explicitly requested

WhenVisible / viewport loading

once()

Included, cached

Reused unless requested

Rarely changing data

always()

Included

Included even when filtered

Critical auth/context

Frontend Partial Reloads

Request specific props from the client:

import { router } from "@inertiajs/react";

// Reload only specific props
router.reload({ only: ["notifications"] });

// Exclude specific props
router.reload({ except: ["stats"] });
import { router } from "@inertiajs/vue3";

router.reload({ only: ["notifications"] });
router.reload({ except: ["stats"] });

Prop Filtering Helpers

Use only() and except_() for server-side filtering:

from litestar_vite.inertia import only, except_

# Include only specific props
filter_users = only("users", "pagination")

# Exclude specific props
filter_no_debug = except_("debug_info", "internal_stats")

# Check if a key should be included
if filter_users.should_include("users"):  # True
    pass
if filter_users.should_include("settings"):  # False
    pass

Protocol Headers

The v2 protocol uses these headers for partial reloads:

Header

Description

X-Inertia-Partial-Data

Comma-separated list of props to include (e.g., users,teams)

X-Inertia-Partial-Except

Comma-separated list of props to exclude (takes precedence over Partial-Data)

X-Inertia-Reset

Comma-separated list of props to reset/remove from shared state

When X-Inertia-Partial-Except is present, it takes precedence over X-Inertia-Partial-Data. This matches the v2 protocol behavior where exclusion is stronger than inclusion.

Reset Props

The X-Inertia-Reset header removes specified props from the shared state:

// Client-side: reset specific props during partial reload
router.reload({
  only: ["users"],
  reset: ["flash", "errors"]  // Clear flash and errors
})

On the backend, reset props are removed from shared_props before building the page response. This is useful for clearing one-time data like flash messages or validation errors.

Example Use Case

Dashboard with heavy charts data:

from typing import Any

from litestar import get
from litestar_vite.inertia import lazy

@get("/dashboard", component="Dashboard")
async def dashboard() -> dict[str, Any]:
    return {
        "user": get_current_user(),              # Always needed
        "summary": get_summary_stats(),          # Always needed
        "charts": lazy("charts", get_chart_data),  # Load on demand
        "activity": lazy("activity", get_activity),  # Load on demand
    }

Frontend:

// Initial load: only user and summary
// Click "Load Charts" button:
router.reload({ only: ["charts"] });

See Also