How to Fix: Route “/” used `Date.now()` instead of using `performance` … when using TanStack react query and dynamicIO
That Date.now() warning on route "/" is not a TanStack Query bug by itself—it happens because a client-side cache is being created during a server render path that must stay compatible with dynamicIO, and somewhere in that initialization path Next.js detects time-based access that should use performance-safe behavior instead.
When you wrap your app with a QueryClientProvider in a layout and instantiate the query client incorrectly, Next.js can treat that work as part of the server-rendered route evaluation. In newer App Router and dynamic rendering flows, that can trigger warnings such as Route “/” used Date.now() instead of using performance. The fix is usually to ensure the React Query provider is a proper client component, that the QueryClient is created only on the client, and that you avoid server-side initialization patterns that leak timing-sensitive APIs into the route render lifecycle.
Table of Contents
Understanding the Root Cause
This issue appears when TanStack React Query is integrated into a Next.js App Router application using a layout-based provider pattern, while the route is being analyzed under dynamicIO rules. The key problem is not the provider itself, but where and when the query client is created.
In many broken setups, developers do one of the following:
- Create a new QueryClient() directly inside a server component.
- Create the client in app/layout.tsx without marking the provider layer as “use client”.
- Instantiate the query client during render in a way that makes Next.js evaluate timing-related internals on the server.
React Query internally tracks freshness, staleness, retries, and cache timestamps. Those mechanisms naturally interact with time APIs. In a normal browser-only context, this is fine. But when the initialization runs through a server-rendered route boundary that Next.js wants to keep deterministic for dynamic rendering analysis, the framework may flag usage patterns involving Date.now().
Why does the warning mention performance? Because frameworks like Next.js increasingly prefer high-resolution or framework-controlled timing behavior for certain execution paths, especially when analyzing render determinism and dynamic usage. If a library or app code touches standard wall-clock time during route evaluation, the route can be marked as using disallowed or unexpected runtime behavior.
So the practical root cause is:
- Your QueryClientProvider is being introduced at the wrong rendering layer.
- The QueryClient is created in a context that Next.js treats as part of the server route execution.
- dynamicIO amplifies this by validating runtime behavior more strictly.
Step-by-Step Solution
The safest fix is to move the React Query provider into a dedicated client component and create the query client lazily on the client side.
1. Create a dedicated provider component
Create a file such as app/providers.tsx:
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'
export default function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
})
)
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
This matters for two reasons:
- ‘use client’ guarantees the provider runs as a client component.
- useState(() => new QueryClient()) ensures the client is created once per browser session lifecycle instead of being recreated during render.
2. Use the provider from your layout
Then keep your layout as a server component, but only render the client provider inside it:
import Providers from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
This is the recommended separation: the layout can stay server-side, while React Query remains isolated in a client boundary.
3. Do not create QueryClient at module scope in shared server/client code
Avoid patterns like this:
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient()
That can be risky in App Router projects because the same module may participate in server evaluation, client bundling, or both. Instead, create the client inside a dedicated client component as shown above.
4. Avoid putting browser cache logic in server components
If you have something like this in a server file, refactor it:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
The problem is that this mixes a client-only stateful cache layer into a server-rendered component tree root.
5. If using hydration, split server prefetching from client provider logic
If your app prefetches data on the server, keep that separate from the client query cache provider. A safer pattern looks like this:
// app/providers.tsx
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'
export function ReactQueryProvider({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(() => new QueryClient())
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
// app/layout.tsx
import { ReactQueryProvider } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<ReactQueryProvider>{children}</ReactQueryProvider>
</body>
</html>
)
}
If you later add dehydration, use the official React Query hydration utilities carefully and keep the browser cache provider inside the client boundary.
6. Upgrade dependencies if the issue persists
This class of issue can also be influenced by framework and library internals. Make sure you test with the latest compatible versions of:
- next
- react
- react-dom
- @tanstack/react-query
Check the TanStack Query repository and the Next.js documentation for any version-specific notes around App Router, server components, and dynamic rendering.
7. Validate the fix
After refactoring:
- Restart the dev server.
- Load route /.
- Confirm the warning about Date.now() no longer appears.
- Verify your React Query hooks still work correctly in client components.
Common Edge Cases
Using useQuery directly in a server component
useQuery is a client-side hook. If you try to use it in a server component, you may get unrelated but confusing errors. Keep query hooks in files marked with ‘use client’.
Recreating the query client on every render
If you write const queryClient = new QueryClient() directly inside the component body without useState, you will recreate the cache repeatedly. That can cause cache loss, refetch loops, and unstable hydration behavior.
Mixing server prefetch and client cache incorrectly
Server prefetching with dehydration is valid, but the boundary must be structured correctly. If dehydration state is prepared on the server while the provider is also incorrectly initialized there, the same route analysis warning can persist.
Strict Mode making the issue seem intermittent
In development, React Strict Mode can re-run logic more than once. If your client creation is not stable, warnings and duplicate requests may appear inconsistently.
Third-party wrappers around QueryClient
If you use a custom abstraction that internally creates a query client, inspect that wrapper. The direct provider code may look correct while the wrapper still performs forbidden initialization during server evaluation.
Outdated examples from older Next.js versions
Some older React Query examples were written before current App Router and server component patterns matured. Reusing those patterns in a modern dynamicIO setup can trigger warnings that did not exist before.
FAQ
1. Is this a bug in TanStack Query?
Not usually. In most cases, this is an integration issue between how the app initializes QueryClient and how Next.js analyzes route execution under dynamicIO. React Query uses time-based cache logic normally; the problem is letting that initialization happen in the wrong render environment.
2. Can I keep the provider in layout.tsx?
Yes, but only indirectly. The recommended pattern is to keep layout.tsx as the server layout and render a separate client component provider inside it. Do not instantiate the query client directly in the server layout.
3. Do I need hydration to fix this warning?
No. Hydration is optional and solves a different concern: transferring prefetched server data into the client cache. The warning is usually fixed simply by moving QueryClientProvider setup into a stable client-only provider.
The reliable fix is straightforward: isolate TanStack React Query behind a ‘use client’ provider, create the QueryClient lazily with useState, and keep server-rendered layouts free of browser-style cache initialization. Once that separation is in place, the Date.now() warning tied to route "/" and dynamicIO typically disappears.