← Back to index

Next.js Strict Mode Debugging Guide

React Strict Mode Impact on Application Behavior

A direct answer for next.js reactstrictmode impact on application behavior: why development renders repeat, why useEffect reruns, why ref callbacks rerun, and whether any of it affects production.

Short Answer

Strict Mode changes development checks, not production behavior. It can make components re-render an extra time, rerun Effects with setup/cleanup, and rerun ref callback functions to expose impure rendering and missing cleanup.

It does not directly change what production users see. If production still has duplicate requests or duplicate subscriptions, the root cause is usually application side effects, dependency handling, caching, or where the request is triggered.

The Next.js App Router defaults to Strict Mode. The official docs state that since Next.js 13.5.1, Strict Mode is enabled by default with the App Router; Pages Router projects can configure it with reactStrictMode in next.config.js.

What Behavior Looks Different?

Symptom Development cause What to inspect
Component functions or console logs appear twice React performs an extra re-render to find render-phase side effects Requests, global writes, mutations of props or state during render
useEffect appears to run twice Effect setup and cleanup are intentionally rerun Missing cleanup, AbortController, unsubscribe logic
Listeners, subscriptions, or timers duplicate Mount cleanup and setup are exercised again removeEventListener, clearInterval, unsubscribe
ref callback or third-party widgets initialize twice Ref callbacks are rerun to reveal missing ref cleanup DOM plugins, charts, maps, dispose/destroy methods

How to Configure reactStrictMode in Next.js

If you use the App Router, you usually do not need to set reactStrictMode: true explicitly. If you use the Pages Router, or your team wants the intent documented in config, put it in next.config.js.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
};

module.exports = nextConfig;

Do not permanently disable Strict Mode just because a development request appears twice. That symptom usually points to a real effect problem: non-idempotent setup, missing cleanup, non-cancelable requests, or stale responses.

Common Mistake: Fetching in an Effect Without Cleanup

Code like this often produces duplicate-looking requests or stale responses during development with Strict Mode:

useEffect(() => {
  fetch(`/api/users/${userId}`)
    .then((res) => res.json())
    .then((data) => setUser(data));
}, [userId]);

A more resilient effect can be cleaned up when the component unmounts or the dependency changes:

useEffect(() => {
  const controller = new AbortController();

  async function loadUser() {
    const res = await fetch(`/api/users/${userId}`, {
      signal: controller.signal,
    });
    const data = await res.json();
    setUser(data);
  }

  loadUser().catch((error) => {
    if (error.name !== "AbortError") {
      throw error;
    }
  });

  return () => controller.abort();
}, [userId]);

If you use React Query, SWR, or server-side data fetching in Next.js, handle duplicate request concerns through caching, deduping, and server/client boundaries instead of adding one-off flags inside components.

Debugging Checklist

FAQ

Does Strict Mode reduce production performance?

No. The extra re-render, Effect rerun, and ref callback rerun behavior is development-only.

Why does the issue disappear when I turn Strict Mode off?

That usually means Strict Mode exposed a side-effect bug. Turning it off hides the symptom, but missing cleanup or impure render logic can still surface during route changes, rapid mount/unmount flows, concurrent rendering, or real user interactions.

What is different between App Router and Pages Router?

The App Router currently defaults to Strict Mode. Pages Router projects generally configure the behavior explicitly with reactStrictMode in next.config.js.

← Metadata and config guide Back to Next.js index →