# HP5004: The page differs after client-side navigation

> HP5004 (navigation-mismatch) means a route renders different content when reached through the app's router than when its URL is loaded directly. Fix it.

Source: https://hydration.jscrate.dev/docs/issues/hp5004
Last updated: 2026-09-18

HP5004 (`navigation-mismatch`) means a route renders different content when you
reach it through the app's router than when you load its URL directly. Users
who arrive from a link see one page, users who reload see another. Render the
route from its own data (params, search params, server data), not from the
previous page or client state.

| | |
| --- | --- |
| Code | `HP5004` |
| Name | `navigation-mismatch` |
| Default severity | Warning |
| Group | Interaction during hydration |
| What it means | Navigating to the route inside the app renders different content than loading the URL directly. |

## What the HP5004 navigation mismatch finding means

The finding comes from the [navigation checks](https://hydration.jscrate.dev/docs/interactions)
(`checks.navigation: true` or `--navigation`). hydration-proof opens a page,
navigates to each route with the app's router (`router.push` in Next.js, the
data router in React Router and Remix) and compares the result with a direct
load. Both loads use the same fixed browser clock and random seed, and numbers
are ignored in the comparison, so time and random values do not cause it:

```text
Navigating to this route from another page renders different content than loading /settings directly (2 differences).
```

The check runs twice per route when the router supports prefetching: once as a
plain navigation and once after the router prefetched the route.

It is a warning. Routes that render parallel routes (`@slot` folders) or that
an intercepting route can replace are reported as info, because the difference
is usually intended there.

## Likely causes

- A layout that keeps state between navigations, such as a selected tab or an
  open panel.
- Module-level variables or a client store filled in by the previous page.
- A component that depends on the previous route, the referrer or history
  state.
- [Different data](https://hydration.jscrate.dev/docs/causes/data) on the client: the route fetches again
  after navigation and gets another result.

## How to fix it

1. **Read data from the route.** Params, search params and server data are the
   same for a direct load and a navigation; the previous page's state is not.
2. **Check layouts that keep state between navigations** and components that
   depend on the previous route. Reset that state when the route changes, or
   move it into the URL.

```tsx title="app/settings/tabs.tsx"
"use client";

import { useSearchParams } from "next/navigation";
import { useSettingsStore } from "./store";

// Before: the tab comes from a store the previous page filled in
export function useActiveTabBefore() {
  return useSettingsStore((state) => state.activeTab);
}

// After: the tab comes from the URL, the same on every kind of load
export function useActiveTab() {
  return useSearchParams().get("tab") ?? "profile";
}
```

To start the navigation from a specific page, set `checks.navigation.from`, or
`navigateFrom` on the route.

## When the difference is intended

A modal from an intercepting route or a slot that keeps its page can differ on
purpose. Add an ignore rule for the route:

```ts title="hydration-proof.config.ts"
import { defineConfig } from "hydration-proof";

export default defineConfig({
  checks: { navigation: true },
  ignore: {
    issues: [
      {
        code: "HP5004",
        route: "/photos/*",
        reason: "Opens as a modal after navigation",
      },
    ],
  },
});
```

See [ignoring findings](https://hydration.jscrate.dev/docs/ignoring) for the other fields.

## Related

- [HP5005: client-side navigation failed](https://hydration.jscrate.dev/docs/issues/hp5005)
- [Interaction and navigation checks](https://hydration.jscrate.dev/docs/interactions)
- [Server and client used different data](https://hydration.jscrate.dev/docs/causes/data)
- [Routes and route options](https://hydration.jscrate.dev/docs/routes)
- [HP5001: a click before hydration was lost](https://hydration.jscrate.dev/docs/issues/hp5001)
