How to Fix: Next js is double rendering components
If your Next.js app appears to render components twice in development, the behavior is usually not a rendering bug in your app at all. In most cases, it is React Strict Mode intentionally mounting, unmounting, and re-mounting components to expose unsafe side effects during development.
Understanding the Root Cause
The issue shown in this reproduction is typically caused by React 18 development behavior inside Next.js. When Strict Mode is enabled, React intentionally runs component initialization paths more than once in development. This includes:
- Calling component functions twice
- Running useEffect setup and cleanup more than once during development checks
- Re-mounting parts of the tree to detect side effects that are not resilient to re-renders
This does not mean production users will see the same behavior. In production builds, React does not perform the same extra development checks.
In a Next.js app, this can be confusing because logs in the console make it look like the framework is rendering the page twice. What is actually happening is one of these scenarios:
- reactStrictMode is enabled in Next.js configuration
- You are testing in development mode with
bun devornext dev - Your component contains side effects directly in the render body, making the double invocation more visible
For example, code like this makes the problem look worse:
export default function Example() {
console.log('rendered');
return <div>Hello</div>;
}
In development with Strict Mode, that console log may appear twice. That is expected.
The deeper reason is that React wants developers to detect code that is unsafe under concurrent rendering. If your component performs mutations, network calls, subscriptions, or object initialization in the wrong place, the extra development render helps expose it early.
Step-by-Step Solution
The right fix depends on whether you want to understand the behavior, verify production output, or disable the extra development check.
1. Confirm it only happens in development
First, run a production build and compare behavior.
bun run build
bun run start
If the component no longer renders twice, the issue is development-only and caused by Strict Mode rather than a runtime bug.
2. Check your Next.js configuration
Open your Next.js config file and look for reactStrictMode.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = nextConfig;
If this is set to true, React will perform extra development checks.
3. Disable Strict Mode temporarily if you need single-render debugging
If your goal is only to stop the duplicate development render while debugging, you can turn it off temporarily.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
};
module.exports = nextConfig;
Then restart the dev server:
bun dev
This removes the extra development render check, but it also removes useful warnings. For most teams, the better approach is to keep Strict Mode on and fix code that depends on render happening only once.
4. Move side effects out of the component body
If you are doing work directly inside the render function, move it into the correct hook.
Problematic:
export default function Page() {
fetch('/api/data');
console.log('render');
return <div>Page</div>;
}
Better:
import { useEffect } from 'react';
export default function Page() {
useEffect(() => {
fetch('/api/data');
}, []);
return <div>Page</div>;
}
Even then, remember that in development useEffect may still appear to run twice under Strict Mode checks. That is expected behavior for development validation.
5. Make effects idempotent
If an effect creates duplicate requests, duplicate listeners, or duplicate analytics events, make it safe to run more than once.
import { useEffect, useRef } from 'react';
export default function Page() {
const hasTracked = useRef(false);
useEffect(() => {
if (hasTracked.current) return;
hasTracked.current = true;
console.log('track page view once');
}, []);
return <div>Page</div>;
}
Use this pattern carefully. It is useful for debugging or one-time client-only integrations, but the best long-term fix is writing effects that can safely mount and clean up correctly.
6. Separate expected development behavior from actual bugs
You may still have a real problem if:
- The duplicate behavior also happens in production
- Your API endpoint is being called twice because of both server and client fetching
- A parent component key changes and forces a remount
- Hot reload is re-triggering renders during editing
That is why checking both dev and production behavior is the fastest way to narrow the cause.
Common Edge Cases
Server and client both fetch the same data
In Next.js, you might fetch on the server and then trigger another fetch on the client. This looks like double rendering, but the actual issue is duplicated data fetching.
export async function getServerSideProps() {
const data = await fetch('https://example.com/api').then(r => r.json());
return { props: { data } };
}
If the page also calls the same API inside useEffect, you will see two requests for different reasons.
Console logs create false alarms
A simple console.log in the component body will run every render. That does not always mean the DOM changed twice. It only proves the function was invoked again.
Hot reload during development
Fast Refresh can re-run component code when files change. This can be mistaken for the same bug, especially when testing with frequent edits.
Changing keys forces remounts
If a parent passes a changing key, React treats the child as a new component and mounts it again.
<MyComponent key={Date.now()} />
This will remount every render and can look like a double-render issue even with Strict Mode disabled.
Third-party libraries with unsafe side effects
Some client-side libraries assume a component mounts exactly once. Under Strict Mode, they may register duplicate listeners or initialize twice unless wrapped carefully with cleanup logic.
FAQ
Why does Next.js render my component twice only in development?
Because React Strict Mode intentionally double-invokes component lifecycle paths in development to detect unsafe side effects. This does not usually happen in production.
Is it safe to disable reactStrictMode?
Yes, technically, but it is usually better to keep it enabled. Disabling it can hide side-effect bugs that may become harder to debug later.
How do I verify whether this is a real bug or expected behavior?
Create a production build and run it locally. If the duplicate render disappears, it is expected development behavior. If it continues, inspect fetch logic, parent keys, remounts, and client/server duplication.
For this GitHub issue, the practical conclusion is: Next.js is not unexpectedly broken here; the observed double render is the expected result of React 18 Strict Mode in development. The fix is either to keep Strict Mode and write side-effect-safe components or to temporarily disable Strict Mode if you need cleaner debugging output.