Preloading in TanStack Router is a way to load a route before the user actually navigates to it. This is useful for routes that are likely to be visited by the user next. For example, if you have a list of posts and the user is likely to click on one of them, you can preload the post route so that it's ready to go when the user clicks on it.
Preloaded route matches are temporarily cached in memory with a few important caveats:
If you need more control over preloading, caching and/or garbage collection of preloaded data, you should use an external caching library like TanStack Query.
The simplest way to preload routes for your application is to set the defaultPreload option to intent for your entire router:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreload: 'intent',
})
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreload: 'intent',
})
This will turn on intent preloading by default for all <Link> components in your application. You can also set the preload prop on individual <Link> components to override the default behavior.
By default, preloading will start after 50ms of the user hovering or touching a <Link> component. You can change this delay by setting the defaultPreloadDelay option on your router:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadDelay: 100,
})
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadDelay: 100,
})
You can also set the preloadDelay prop on individual <Link> components to override the default behavior on a per-link basis.
If you're using the built-in loaders, you can control how long preloaded data is considered fresh until another preload is triggered by setting either routerOptions.defaultPreloadStaleTime or routeOptions.preloadStaleTime to a number of milliseconds. By default, preloaded data is considered fresh for 30 seconds..
To change this, you can set the defaultPreloadStaleTime option on your router:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadStaleTime: 10_000,
})
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadStaleTime: 10_000,
})
Or, you can use the routeOptions.preloadStaleTime option on individual routes:
// src/routes/posts.$postId.tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
// Preload the route again if the preload cache is older than 10 seconds
preloadStaleTime: 10_000,
})
// src/routes/posts.$postId.tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
// Preload the route again if the preload cache is older than 10 seconds
preloadStaleTime: 10_000,
})
When integrating external caching libraries like React Query, which have their own mechanisms for determining stale data, you may want to override the default preloading and stale-while-revalidate logic of TanStack Router. These libraries often use options like staleTime to control the freshness of data.
To customize the preloading behavior in TanStack Router and fully leverage your external library's caching strategy, you can bypass the built-in caching by setting routerOptions.defaultPreloadStaleTime or routeOptions.preloadStaleTime to 0. This ensures that all preloads are marked as stale internally, and loaders are always invoked, allowing your external library, such as React Query, to manage data loading and caching.
For example:
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadStaleTime: 0,
})
import { createRouter } from '@tanstack/react-router'
const router = createRouter({
// ...
defaultPreloadStaleTime: 0,
})
This would then allow you, for instance, to use an option like React Query's staleTime to control the freshness of your preloads.
If you need to manually preload a route, you can use the router's preloadRoute method. It accepts a standard TanStack NavigateOptions object and returns a promise that resolves when the route is preloaded.
function Component() {
const router = useRouter()
useEffect(() => {
try {
const matches = await router.preloadRoute({
to: postRoute,
params: { id: 1 },
})
} catch (err) {
// Failed to preload route
}
}, [])
return <div />
}
function Component() {
const router = useRouter()
useEffect(() => {
try {
const matches = await router.preloadRoute({
to: postRoute,
params: { id: 1 },
})
} catch (err) {
// Failed to preload route
}
}, [])
return <div />
}
If you need to preload only the JS chunk of a route, you can use the router's loadRouteChunk method. It accepts a route object and returns a promise that resolves when the route chunk is loaded.
function Component() {
const router = useRouter()
useEffect(() => {
try {
const postsRoute = router.routesByPath['/posts']
await Promise.all([
router.loadRouteChunk(router.routesByPath['/']),
router.loadRouteChunk(postsRoute),
router.loadRouteChunk(postsRoute.parentRoute),
])
} catch (err) {
// Failed to preload route chunk
}
}, [])
return <div />
}
function Component() {
const router = useRouter()
useEffect(() => {
try {
const postsRoute = router.routesByPath['/posts']
await Promise.all([
router.loadRouteChunk(router.routesByPath['/']),
router.loadRouteChunk(postsRoute),
router.loadRouteChunk(postsRoute.parentRoute),
])
} catch (err) {
// Failed to preload route chunk
}
}, [])
return <div />
}
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.