Why `router.push()` Does Not Refresh Data in Next.js

Navigating back to a route you already visited can show stale data. Learn why push alone does not refetch, and which method actually pulls fresh data.

7 min read

A router.push() stale data problem shows up when you navigate to a route a reader already visited: the page can render old content, even after the underlying data changed on the server. This happens because push performs a client-side navigation using Next.js's in-memory client cache whenever a match is available, rather than always asking the server for the latest data.

Reproducing the problem

Say a settings page updates a display name, then navigates back to a profile route the reader visited a moment earlier in the same session.

App.tsxApp.tsx
// app/settings/save-button.tsx
"use client";
import { useRouter } from "next/navigation";
export default function SaveButton({ onSave }: { onSave: () => Promise<void> }) {
  const router = useRouter();
  const handleSave = async () => {
    await onSave();
    router.push("/profile");
  };
  return <button onClick={handleSave}>Save</button>;
}

If the profile route was already cached from an earlier visit, this navigation can render that cached version first, still showing the old display name, since a plain navigation has no built-in refetch step of its own.

Why this happens

The App Router keeps visited and prefetched routes in an in-memory client cache so that navigating back to them feels instant instead of triggering a new server request every time. That speed is the whole point of the cache, but it means a plain navigation can serve content that was correct when it was cached and is now out of date on the server.

The fix inside the current route

Call refresh right after the mutation to re-fetch the current route's data from the server and re-render its Server Components, without losing client-side state such as scroll position or an open menu.

App.tsxApp.tsx
"use client";
import { useRouter } from "next/navigation";
export default function SaveButton({ onSave }: { onSave: () => Promise<void> }) {
  const router = useRouter();
  const handleSave = async () => {
    await onSave();
    router.refresh();
    router.push("/profile");
  };
  return <button onClick={handleSave}>Save</button>;
}

This method always targets whichever route the reader is currently on. It does not accept a different route as an argument, so it cannot force a route the reader has not visited yet to update in advance of them getting there.

The fix for every reader, not just this one

When a mutation should invalidate a route's data everywhere, not only in the browser that made the change, use a server-side revalidation function inside the Server Action instead of relying on a client-side refresh.

revalidatePath and revalidateTag invalidate cached data from a Server Action or a Route Handler, and they work whether or not a project has Cache Components enabled. Inside a Server Action specifically, prefer updateTag for data cached with cacheTag under the use cache directive: it expires that tag immediately instead of serving stale content while a background refresh completes, so the reader who just made the change sees it right away.

For the full set of router methods this article builds on, see useRouter in the App Router: Push, Replace, Refresh, and Back. To see how a redirect after a Server Action differs from this client-side pattern, read useRouter vs redirect in Next.js: Client vs Server Navigation.

Rune AI

Rune AI

Key Insights

  • push reuses cached route data when it is available instead of always fetching fresh data.
  • refresh re-fetches the current route's data from the server without a full reload.
  • refresh always targets the route you are currently on, not a route you pass in.
  • revalidatePath and revalidateTag stay current in Next.js 16 and work with or without Cache Components enabled.
  • updateTag only runs inside a Server Action and invalidates a cacheTag immediately instead of serving stale content first.
RunePowered by Rune AI

Frequently Asked Questions

Does a full browser refresh always show fresh data?

Yes. Pressing F5 bypasses the client cache entirely and always requests fresh data from the server, unlike a push navigation which may reuse a cached route.

Does router.refresh accept a route as an argument?

No. It always refreshes the route the reader is currently on. To force a specific route's data to update everywhere, use a server-side revalidation function instead.

Is revalidatePath the current way to invalidate data in Next.js 16?

Yes. revalidatePath and revalidateTag are still current and work with or without Cache Components enabled. Inside a Server Action, updateTag is the better choice for data cached with cacheTag, since it invalidates immediately instead of serving stale content during a background refresh.

Conclusion

push alone only performs a client-side navigation using whatever is already in the client cache, so a revisited route can show data that no longer matches the server. Call refresh to pull fresh data into the current route, or use a server-side revalidation function so every reader sees the update after a mutation.