When `cacheComponents` is enabled, the App Router preserves state across
navigations by rendering inactive routes inside React `<Activity>`
boundaries.
As a default behavior, this is a huge convenience because it lets you
navigate between routes without resetting or losing ephemeral UI state
(scroll position, expand/collapse, in-progress form edits). Previously
the only way to do this was to explicitly track each state with an
external state manager, or hoist it to a parent component.
It's still the often the case that you should be explicitly tracking all
important UI state, anyway, so that it survives a hard refresh of the
app, or the browser window being accidentally closed. For example, forms
draft states should be persisted to a server-side database or local
storage engine. If you're already doing that, then it doesn't matter so
much whether client state is preserved via `<Activity>` boundaries or
not.
For the long tail of ephemeral state that is not tracked, Next.js's
philosophy is that it's a better UX default to preserve as much
emphemeral state as possible. It's easier to model the cases where you
_do_ want state to be reset on navigation as exceptions, compared to the
other way around.
However, this is a significant change compared to the pre-Cache
Components previous behavior of Next.js, and compared to other web
frameworks, and indeed the browser's own native bfcache (which
implements state restoration for history traversal navigations only, not
push/replace).
There's are also lots of existing codebases that may rely on the current
behavior, and may break subtly under these new semantics. Even if this
new default unlocks better UX patterns, we don't want to force everyone
to migrate all their code all at once.
So, this PR introduces a drop-in mechanism for opting out of state
preservation when navigating to a previously visited route.
The API is exposed as `useRouter().bfcacheId`. It's intended to be
passed to a React `key`:
<form key={useRouter().bfcacheId}>
The id is contextual: read from a layout, you get the layout's id; read
from a page, you get the page's id. It's stable across back/forward
navigations, `router.refresh()`, server actions that call `refresh()`,
and search-param- or hash-only navigations — i.e., any time the
surrounding segment is preserved. It changes when the segment is freshly
created by a push or replace into a different route.
An important detail is that the previous id is restored during a back/
foward navigation. So state preservation will still work if you navigate
via the browser's back button.
Why add this to `useRouter()` instead of giving it its own hook? The
intent is communicate that `bfcacheId` is not considered an idiomatic
pattern — the recommended fix for "I want this state to reset on
navigation" is almost always something else: an explicit reset in a
submit handler, or a key derived from the underlying data (e.g., a draft
id from the server). `useRouter` is the hook where we expose low-level
APIs that are supported but are only recommended for advanced or
exceptional cases. (For example, instead of `router.push()`, you should
almost always use a `<Link>` component instead.)
Getting Started
Used by some of the world's largest companies, Next.js enables you to create full-stack web applications by extending the latest React features, and integrating powerful Rust-based JavaScript tooling for the fastest builds.
- Visit our Learn Next.js course to get started with Next.js.
- Visit the Next.js Showcase to see more sites built with Next.js.
Documentation
Visit https://nextjs.org/docs to view the full documentation.
Community
The Next.js community can be found on GitHub Discussions where you can ask questions, voice ideas, and share your projects with other people.
To chat with other community members you can join the Next.js Discord server.
Do note that our Code of Conduct applies to all Next.js community channels. Users are highly encouraged to read and adhere to it to avoid repercussions.
Contributing
Contributions to Next.js are welcome and highly appreciated. However, before you jump right into it, we would like you to review our Contribution Guidelines to make sure you have a smooth experience contributing to Next.js.
Good First Issues:
We have a list of good first issues that contain bugs that have a relatively limited scope. This is a great place for newcomers and beginners alike to get started, gain experience, and get familiar with our contribution process.
Security
If you believe you have found a security vulnerability in Next.js, we encourage you to responsibly disclose this and NOT open a public issue.
To participate in our Open Source Software Bug Bounty program, please email [email protected]. We will add you to the program and provide further instructions for submitting your report.