How it works
Fast Refresh has three update modes depending on what you edited:Pure component file
Pure component file
If the file only exports React components, Fast Refresh updates only that file and re-renders the component. Styles, rendering logic, event handlers, and effects can all be edited this way.
Mixed exports
Mixed exports
If the file exports something that is not a React component, Fast Refresh re-runs that file and all files that import it. Both
Button.js and Modal.js will update if they both import a shared theme.js that you edited.Outside the React tree
Outside the React tree
If an edited file is imported by non-React code, Fast Refresh falls back to a full page reload. To avoid this, consider moving shared constants or utilities to a separate file so each module has a clear purpose.
Preserving component state
Fast Refresh preserves local state in function components and hooks between edits:useStateanduseRefkeep their values as long as you don’t change the order of hook calls or their arguments.- Hooks with dependencies (
useEffect,useMemo,useCallback) always re-run during Fast Refresh — their dependency arrays are ignored so that your edits take effect immediately.
Even a
useEffect with an empty dependency array ([]) will re-run once during a Fast Refresh update. Writing effects that are resilient to re-running is a good practice — it is also enforced by React Strict Mode.Force a full remount
If you need to reset all component state during development (for example, when testing a mount animation), add the// @refresh reset directive anywhere in the file:
Error recovery
Syntax errors
When you introduce a syntax error, Next.js displays an overlay. Fix the error and save — the overlay dismisses automatically and the app continues without losing component state.Runtime errors
A runtime error inside a component shows a contextual overlay with a stack trace. Fixing the error dismisses the overlay without a full reload. If the error occurred during rendering, React remounts the application from the updated code. If the error occurred elsewhere (for example, in an event handler), component state is retained. Error boundaries in your app will retry rendering on the next edit after a rendering error. This prevents always resetting to the root state, but error boundaries should be intentional and not too granular.Limitations
Fast Refresh does not preserve local state in these situations:| Situation | Reason |
|---|---|
| Class components | Only function components and hooks preserve state |
| File has non-component exports | Fast Refresh cannot safely distinguish which export changed |
| Higher-order component returning a class | HOC(WrappedComponent) — the returned class state is reset |
| Anonymous default export | export default () => <div /> — no stable component identity |
Connection to React reconciliation
Fast Refresh is built on top of React’s reconciliation algorithm. When a module update arrives:- React receives the new component definition.
- The reconciler compares the new and previous component trees.
- If the component identity (function reference) is stable, React updates in place and state is preserved.
- If the identity changed (for example, due to a class component or an anonymous function), React unmounts and remounts the subtree.
__SECRET_INTERNALS and the react-refresh runtime to register updated components and trigger this targeted re-render.
Tips
- You can add
console.logordebuggerstatements directly in components while editing. They take effect immediately without a reload. - Imports are case-sensitive. A mismatch between
'./header'and'./Header'will cause both fast and full refresh to fail. - The
// @refresh resetdirective only affects the file it is in.
