Preloading and Caching

Purpose and Scope

Preloading is the Router feature that starts preparing a destination route before the final navigation happens. In practical terms, it lets a link turn a likely future click into work that can begin during hover, touch, visibility, or render time. TanStack Router frames this as part of data-driven navigation: the router already knows where users may go, which route matches will be involved, and which async requirements belong to those matches. This page explains how preloading strategies, stale lifetimes, garbage collection lifetimes, loader caching, and per-link overrides fit together for application authors.

Sources: docs/router/guide/preloading.md, docs/router/guide/data-loading.md

Preloading is related to, but not identical to, normal route loading. Normal loading follows a URL or history update and moves through matching, pre-loading checks, and parallel loading for components and route loaders. Preloading instead prepares route matches speculatively. If the user follows through, the preloaded route state can be promoted into the router's normal pending matches state. If the user does not navigate, the data remains temporary and is later removed according to the configured preloading cache behavior.

Sources: docs/router/guide/preloading.md, docs/router/guide/data-loading.md

Relevant Source Files

  • docs/router/guide/preloading.md - Defines the supported preloading strategies, default preload enablement, preload delay, and freshness and memory lifetime controls for preloaded matches.
  • docs/router/guide/data-loading.md - Explains why the router coordinates async dependencies, describes the route loading lifecycle, and positions the built-in router cache against TanStack Query.
  • docs/router/api/router/RouterOptionsType.md - Provides the router-level options that configure default preloading strategy, delay, stale time, preload garbage collection, general stale time, and stale reload behavior.
  • docs/router/api/router/LinkOptionsType.md - Defines link-level options for overriding preload behavior, including strategy and delay, alongside standard link concerns such as target, active options, and disabled rendering.

Core Preloading Strategies

TanStack Router supports three named preload strategies plus disabling preload. The intent strategy reacts to user intent on a link, specifically hover and touch start interactions, and is the most common default because it waits for a signal that the user may navigate. The viewport strategy uses browser visibility through the Intersection Observer API so a link can start preparing its destination when it appears on screen. The render strategy begins preloading as soon as the link is rendered in the DOM, which is useful for destinations that are effectively guaranteed to be needed.

Sources: docs/router/guide/preloading.md, docs/router/api/router/RouterOptionsType.md

Choosing a strategy is a balance between responsiveness and unnecessary work. Intent preloading usually has the best signal-to-cost ratio because it delays work until a user interacts with a link. Viewport preloading is useful for lists, cards, or below-the-fold links where the user may scroll into a set of destinations and then choose one. Render preloading is more aggressive and should be reserved for routes whose dependencies are small or almost certainly needed. Disabling preloading remains appropriate for expensive routes, rarely visited destinations, or links whose target changes frequently.

Sources: docs/router/guide/preloading.md, docs/router/api/router/LinkOptionsType.md

Router-Level Defaults

The simplest application-wide setup is to configure the router with a default preload strategy. The RouterOptions API documents defaultPreload as accepting false, intent, viewport, or render, with false as the default. The guide recommends defaultPreload set to intent as the easiest way to make all Link components participate in preloading by default. This keeps individual links simple while still allowing targeted overrides where one route should preload more aggressively, less aggressively, or not at all.

Sources: docs/router/guide/preloading.md, docs/router/api/router/RouterOptionsType.md

import { createRouter } from '@tanstack/react-router'
 
const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
})

Preload delay is another router-level default. For intent preloading, TanStack Router waits briefly before starting the preload so accidental pointer movement or very short touches do not immediately trigger network and module work. The documented default is fifty milliseconds. Applications can raise that value with defaultPreloadDelay when they want stronger intent confirmation, or lower it when they prefer faster speculative loading. The same delay can be overridden per link, so teams can use conservative global settings and then tune high-value links individually.

Sources: docs/router/guide/preloading.md, docs/router/api/router/RouterOptionsType.md

const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  defaultPreloadDelay: 100,
})

LinkOptions extends navigation options with anchor and router-specific behavior. For preloading, the important properties are preload and preloadDelay. The preload property can set a specific strategy or false for that link, overriding the router default. The preloadDelay property delays intent preloading by the configured number of milliseconds and cancels the preload if intent exits before the delay completes. This is the right layer for local decisions such as turning off preloading for an administrative export route or using viewport preloading for a list of article cards.

Sources: docs/router/api/router/LinkOptionsType.md, docs/router/guide/preloading.md

<Link to="/posts/$postId" params={{ postId }} preload="intent" preloadDelay={75}>
  Read post
</Link>
 
<Link to="/reports/heavy" preload={false}>
  Heavy report
</Link>

A useful pattern is to establish intent preloading globally and then reserve per-link configuration for exceptions. For example, a product grid can use viewport preloading on product detail links because links entering the viewport are strong candidates for later clicks. A settings page link might rely on the global intent default. A destructive or resource-heavy workflow can disable preloading. This keeps the application policy understandable while still reflecting the fact that different destinations have different cost profiles, freshness requirements, and likelihood of being visited.

Sources: docs/router/guide/preloading.md, docs/router/api/router/LinkOptionsType.md

Cache Lifetimes and Freshness

Preloaded route matches are cached temporarily in memory. The preloading guide states that unused preloaded data is removed after thirty seconds by default and that this can be configured through defaultPreloadMaxAge. The RouterOptions API also exposes defaultPreloadStaleTime, defaultPreloadGcTime, and defaultGcTime. In reader-facing terms, freshness answers whether another preload should run, while garbage collection answers how long unused preload data may remain in memory. Loaded matches move out of the speculative preload state and into the router's normal pending and loaded match lifecycle.

Sources: docs/router/guide/preloading.md, docs/router/api/router/RouterOptionsType.md

When using built-in route loaders, defaultPreloadStaleTime and route-level preloadStaleTime control how long preloaded data is considered fresh. The documented default is thirty seconds. During that freshness window, another preload for the same route data should not be triggered merely because the link receives another preload signal. Separately, defaultPreloadGcTime controls how long preloaded data can remain before garbage collection, defaulting to the router's general garbage collection time. These settings let an application reduce duplicate work without keeping speculative data indefinitely.

Sources: docs/router/guide/preloading.md, docs/router/api/router/RouterOptionsType.md

const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  defaultPreloadStaleTime: 10_000,
  defaultPreloadDelay: 100,
})

Relationship to Data Loading

The data loading guide explains that routing is the best place to coordinate page async dependencies because it knows where users are headed before rendering content. TanStack Router route loaders can fetch data per route, in parallel, and participate in suspense. The same guide describes the built-in router cache as stale-while-revalidate caching for loader data. Preloading benefits from this model: a destination can have its code and loader work prepared early, so the eventual navigation has less work left before content can appear.

Sources: docs/router/guide/data-loading.md, docs/router/guide/preloading.md

The built-in router cache is intentionally convenient rather than a complete application data platform. The data loading guide lists strengths such as no extra dependencies, deduping, preloading, loading, stale-while-revalidate behavior, background refetching, coarse invalidation, automatic garbage collection, and SSR compatibility. It also calls out limitations: no persistence adapters, no shared cache between routes, no built-in mutation APIs, and no cache-level optimistic update APIs. If your application needs those capabilities, the preloading guide recommends using an external caching library such as TanStack Query for more control.

Sources: docs/router/guide/data-loading.md, docs/router/guide/preloading.md

Compact Reference

ConcernRouter-level optionLink or route-level optionDefault or behavior
Enable preloadingdefaultPreloadpreloadfalse globally; link can choose intent, viewport, render, or false
Intent delaydefaultPreloadDelaypreloadDelay50 milliseconds by default; cancelled if intent exits before delay
Preload freshnessdefaultPreloadStaleTimeroute preloadStaleTime30 seconds by default for built-in loaders
Preload garbage collectiondefaultPreloadGcTimeroute preloadGcTime where supported by route optionsDefaults to defaultGcTime, which defaults to 30 minutes in the RouterOptions API
Normal stale reloaddefaultStaleReloadModeloader or route configuration depending on loading setupbackground by default, with blocking available for stale successful loader reloads

Use router defaults for the broad policy and link overrides for exceptions. Start with intent preloading if the application benefits from faster perceived navigation and the destination loaders are reasonably cheap. Add viewport preloading for visible collections where the next likely action is a detail navigation. Use render preloading sparingly for destinations that should always be ready. Tune stale time before garbage collection time: freshness reduces repeat work, while garbage collection manages memory for speculative data the user never consumed.

Sources: docs/router/api/router/RouterOptionsType.md, docs/router/api/router/LinkOptionsType.md, docs/router/guide/preloading.md

Practical Next Steps

To adopt preloading safely, first identify the routes where faster navigation matters most, such as detail pages from lists or common dashboard tabs. Configure defaultPreload at the router level only after considering the cost of route loaders and component preloads. Then audit expensive links and disable or delay their preloads. Finally, decide whether the built-in router cache is sufficient for your data model. If data is shared across many routes, needs persistence, or requires mutation and optimistic update workflows, pair Router navigation with a dedicated data cache rather than stretching route preloading beyond its intended role.

Sources: docs/router/guide/preloading.md, docs/router/guide/data-loading.md

Related pages: Data Loading, External Data Loading and Mutations, Navigation and Links, Router Options, State, and Events