router icon indicating copy to clipboard operation
router copied to clipboard

Run loader on client and server

Open ilarramendi opened this issue 7 months ago • 2 comments

Which project does this relate to?

Start

Describe the bug

I'm using TanStack Start with TanStack Query and noticing that preloaded query data can become stale when served from SSR.

I’m using defaultPreloadStaleTime: 0, which I’d expect to cause the loader to run on both the server and the client, ensuring fresh data even after SSR and hydrating the queries in the client. But currently, the loader only runs on the server during the initial page render.

If that server-rendered response is cached (e.g. by a CDN or browser), the client doesn't re-run the loader, so the data can remain stale untill its used by a component, when it should be refreshed by the loader.

Your Example Website or App

https://stackblitz.com/github/tanstack/router/tree/main/examples/react/start-basic-react-query

Steps to Reproduce the Bug or Issue

I think this is an expected behavior but this can be tested just adding a log to any loader using start

Expected behavior

defaultPreloadStaleTime being taken into consideration and run the loader in the client side too if it makes sense based on the configure time

Screenshots or Videos

No response

Platform

  • OS: any
  • Browser: any
  • Version: latest/alpha

Additional context

No response

ilarramendi avatar Jun 07 '25 23:06 ilarramendi

defaultPreloadStaleTime does not affect data that the router was hydrated with, it's only for client-side preloading (e.g. upon link hover).

Can you please explain in more detail what you mean here?

If that server-rendered response is cached (e.g. by a CDN or browser), the client doesn't re-run the loader, so the data can remain stale untill its used by a component, when it should be refreshed by the loader.

schiller-manuel avatar Jun 08 '25 00:06 schiller-manuel

Why doesn’t defaultPreloadStaleTime apply to data preloaded on the server as well? If I set it to 0 and hover over a link, the loader runs. If I hover again, it runs again — as expected. So on the initial page load, shouldn’t the loader also run on the client if the time between the server preloading the data and the client starting up exceeds defaultPreloadStaleTime?

Here’s the situation: I’ve got a route with a loader that calls prefetchQuery. Since I’m using @tanstack/react-router-with-query, the query data is included in the SSR response. The issue is that the router doesn’t re-run the loader on the client. So if the SSR response is cached by a CDN, that data might be stale — and it won't be refreshed by the loader, only by the component using the query.

That’s also why I believe the loader should run on both the server and the client. Also it would let me differentiate behavior based on environment. For example, I don’t preload user-specific data on the server because the SSR response is cached and shared across users. But I still want to preload the user profile on the client after hydration, while keeping SSR support for rendering the public parts of the site.

Edit: On a related note, I’m trying to split my translations into separate bundles for performance reasons. I’ve set up a solution that loads the translations in the root loader, and it works as expected on the server side. The initial render includes the correct translations from the backend. However, on the client, the translations aren’t actually loaded after hydration since the loader dosnt run — they only load when I hover over a link.

ilarramendi avatar Jun 08 '25 02:06 ilarramendi