ix
ix

informatix

PL version Book a discovery call
Home / Blog / Inertia.js Performance Optimization — Bundle, Prefetch and C...
• 8 min read •

Inertia.js Performance Optimization — Bundle, Prefetch and Caching [2026]

Inertia.js performance problems are predictable: oversized props, a growing bundle, full-page reloads and N+1 queries. A practical checklist ordered by return on effort, with a performance budget.

Inertia.js Performance Optimization — Bundle, Prefetch and Caching [2026]
Web development

Inertia.js is fast by default, but production applications slow down for predictable reasons: oversized props, a single JavaScript bundle that grows with every page, unnecessary full-page reloads and a database that runs an N+1 query behind every list. This guide is a practical performance checklist for Laravel + React + Inertia, ordered by return on effort.

Key takeaway: The short version — split pages into separate chunks, send only the props the UI needs, use partial reloads and deferred props, prefetch likely next pages, cache expensive queries, eliminate N+1 and monitor the SSR process. Measure before and after; do not optimize by intuition.

Where Inertia performance problems come from

Inertia adds one thing to a Laravel application: a JSON payload with the page component and props. The performance profile is therefore dominated by:

  1. Payload size — how much data each page sends.
  2. Bundle size — how much JavaScript the browser must download and parse.
  3. Request count — how many visits and partial reloads the UI triggers.
  4. Database work — how many queries run to build the props.
  5. Rendering — whether SSR is enabled and whether the SSR process is healthy.

Most "Inertia is slow" reports turn out to be a 2 MB JSON payload, a 1.5 MB bundle or a 300-query dashboard — not a problem with Inertia itself.

Measure first

Use the same tools you would use for any Laravel application

Tool What it shows
Laravel Debugbar query count, duplicates, timeline (local)
Laravel Telescope requests, queries, jobs, exceptions (staging)
Laravel Pulse slow queries, slow endpoints, cache and queues (production)
Lighthouse / PageSpeed Insights LCP, INP, CLS, bundle opportunities
WebPageTest waterfall, filmstrip, caching
Vite bundle analyzer which chunks are large and why

Measure the three most important screens, not the whole app. If the dashboard is slow and the settings page is fine, optimize the dashboard.

Code splitting

The default import.meta.glob('./Pages/**/*.jsx', { eager: true }) imports every page into the main bundle. That is convenient in development and expensive in production.

Use lazy imports

const pages = import.meta.glob('./Pages/**/*.jsx');

Each page becomes a separate chunk, loaded only when the user visits it. Combine this with a loading state

createInertiaApp({
    resolve: async (name) => {
        const pages = import.meta.glob('./Pages/**/*.jsx');
        const page = await pages[`./Pages/${name}.jsx`]();
        return page;
    },
});

Check the build output. A page that imports a charting library, a rich text editor or a date library should be its own chunk. If the shared vendor chunk is still large, inspect it with vite-bundle-visualizer and replace or lazy-load heavy dependencies.

Props discipline

Every prop is serialized to JSON, sent over the network and hydrated in the browser. Treat props like an API response.

  • Use API Resources to select only the columns the UI needs.
  • Paginate lists; never send 10,000 rows.
  • Avoid nested models with all relations loaded. Shape the data for the screen.
  • Do not share expensive data in HandleInertiaRequests::share() on every request.
  • Use withCount() instead of loading a relation just to count it.
return Inertia::render('Orders/Index', [
    'orders' => OrderResource::collection(
        Order::query()
            ->select(['id', 'customer_id', 'total', 'status', 'created_at'])
            ->with('customer:id,name')
            ->latest()
            ->paginate(20)
    ),
]);
  • A useful rule: if a prop is not visible on the first screen and is not needed for interaction, defer it.

Partial reloads and deferred props

A filter change should not reload the whole page. Use partial reloads

router.reload({ only: ['orders'] });

Heavy secondary data should load after the first render

return Inertia::render('Dashboard', [
    'stats' => Inertia::defer(fn () => $this->stats()),
    'audit' => Inertia::optional(fn () => $this->auditLog()),
]);
<Deferred data="stats" fallback={<Skeleton />}>
    {(stats) => <StatsGrid stats={stats} />}
</Deferred>

This improves perceived performance even when the total data volume is unchanged: the page becomes interactive sooner and the user sees the primary content first.

Prefetching

Inertia can prefetch a page before the user clicks

<Link href="/orders" prefetch="hover">Orders</Link>
<Link href="/reports" prefetch="mount">Reports</Link>
  • hover is cheap and safe for most navigation.
  • mount is aggressive; use it only for the most likely next page.
  • Prefetching does not help if the page payload is huge — fix the payload first.

Caching

Cache data that does not change on every request

$stats = Cache::remember('dashboard:stats', now()->addMinutes(5), fn () =>
    Order::query()->selectRaw('status, count(*) as total')->groupBy('status')->get()
);

For expensive pages, cache the rendered fragment or the API resource collection. Invalidate with tags (Redis) or key versioning, not Cache::flush().

HTTP caching is also useful for public pages: Cache-Control: public, s-maxage=60, stale-while-revalidate=300 at the CDN or reverse proxy. Do not cache authenticated pages.

Database and N+1

Inertia makes N+1 visible because the query runs while building props. Enable Model::preventLazyLoading() in development and add query budget assertions to your tests.

Order::with('customer', 'items.product')->paginate(20);

Use withCount(), withSum() and withAvg() for aggregates. Add indexes for the columns used in filters and sorting. See the Laravel performance guide for the full database checklist.

SSR performance

SSR improves first paint but adds a Node process. Keep it healthy and fast

  • Build the SSR bundle in CI and deploy it with the application.
  • Run the SSR server under Supervisor or systemd with a restart policy.
  • Monitor memory and response time; restart on leaks.
  • Do not run heavy queries twice (once for SSR, once for hydration). Cache shared data.
  • Use stale-while-revalidate for public pages where appropriate.
  • If SSR is down, Inertia falls back to client rendering — fast to recover, bad for SEO. Alert on it.

Laravel Octane

Inertia works with Octane, but Octane keeps the application in memory between requests. Watch for

  • static state and singletons that leak between users;
  • shared props that capture the first request's user;
  • Inertia responses cached accidentally;
  • memory growth in long-running workers.

Test with a staging environment and a load test before switching production. For most applications, OPcache and PHP-FPM tuning deliver most of the benefit with less risk.

Performance budget

A practical budget for a SaaS page

Metric Target
JavaScript per route (gzip) < 200 KB
LCP (mobile) < 2.5 s
INP < 200 ms
CLS < 0.1
TTFB < 500 ms
Props payload < 100 KB per page

Track the budget in CI with Lighthouse CI. A performance regression is easier to fix in a pull request than in production.

Checklist

  • Lazy page imports and separate chunks.
  • API Resources and selected columns.
  • Pagination on every list.
  • Partial reloads for filters and pagination.
  • Deferred props for heavy secondary data.
  • Prefetch on hover for likely navigation.
  • Cache for expensive queries.
  • No N+1 queries.
  • SSR process monitored.
  • Lighthouse CI budget enforced.
  • Octane tested before enabling.

FAQ

Why is my Inertia page slow on the first load?

Usually a large JavaScript bundle or a large props payload. Check the build output and the JSON size, then split pages and reduce props.

Does Inertia send all props on every visit?

It sends the props returned by the controller. Use partial reloads to request only what changed and deferred props for heavy data.

Is SSR faster than client-side rendering?

SSR improves first contentful paint and SEO, but it adds server cost. It is not automatically faster for every interaction; client-side navigation is still fast after hydration.

How do I reduce the JavaScript bundle?

Use lazy import.meta.glob, split heavy pages, replace large dependencies, and analyze the bundle with vite-bundle-visualizer.

Does prefetching improve performance?

It improves perceived performance for likely navigation. It does not reduce total bytes; use it selectively.

Can I use React Query with Inertia?

You can, but you usually do not need it. Inertia already handles server state through props. Use React Query for client-side data that is not part of the page visit.

How do I measure Inertia performance in production?

Use Laravel Pulse for slow endpoints and queries, and Chrome UX Report or PageSpeed Insights for field Core Web Vitals.

Sources


Need help making an Inertia.js application faster? Check our Laravel development services or hire a Laravel developer.

Read more: Inertia.js with Laravel and React, Laravel performance optimization, Inertia.js SEO guide and Inertia.js SSR with Laravel.

KS

Krzysztof Słonina

Full stack developer and owner of Inoventis Solutions (informatix). Since 2009 he has built Laravel/PHP web applications, e-commerce integrations and process automations — including OneCRMApp and FamilyTimelineApp, both running on Laravel, React and Inertia.js.

About the author

Related posts

09.10.2026

Laravel Performance Optimization — Practical Guide [2026]

Slow apps lose users and revenue. A complete Laravel performance guide — from measurement and N+1 queries, through caching, queues and indexes, to OPcache, PHP-FPM and Laravel Octane. With a deployment checklist and costs.

Read more