FirebaseReactNext.jsRoutingState Management

Breaking the Firebase Auth Infinite Redirect Loop

Stop the flickering screen of death. Here's how to stabilize your React Firebase `onAuthStateChanged` listeners and routing.

K

Khadar Baba

Full Stack & Debugging Engineer

9 min read
Updated 5/9/2026
Urgency: HighTested against Next.js 14 & Firebase v10 • Last verified May 2026

Quick Answer

Firebase auth redirect loops in Next.js usually occur when routing logic evaluates before the asynchronous onAuthStateChanged listener finishes. To fix this, implement a loading state in your AuthContext and block all router redirects until loading is false.

Similar Error Patterns

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
FirebaseError: Firebase: Error (auth/network-request-failed).
NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted

Are You Seeing This?

  • Flickering screen when loading the dashboard
  • Infinite loop between /login and /dashboard
  • Maximum update depth exceeded error in console
  • Users are redirected to login even if they were previously logged in

One of the most frustrating experiences for a user is attempting to log in, only to be caught in an infinite loop of redirects between the login page and the dashboard, accompanied by a rapidly flickering UI.

This infinite loop is a classic race condition in React and Next.js applications using Firebase Authentication. It occurs when your application's routing logic evaluates the user's authentication state before Firebase has had time to retrieve the token from the browser's IndexedDB.

TL;DR: How to fix the Firebase Auth Loop

  • 11. Isolate the Firebase `onAuthStateChanged` listener inside a dedicated React Context Provider.
  • 22. Introduce a `loading` state flag that initializes as `true`.
  • 33. Block Next.js or React Router from evaluating redirect logic until `loading` is `false`.
  • 44. Ensure `useEffect` dependency arrays monitoring the auth state do not contain continuously updating variables.

Root Causes

Asynchronous Auth Initialization (The Race Condition)

When a React app mounts, Firebase takes a few milliseconds to check local storage/IndexedDB for an existing session. If your Next.js router checks `currentUser` synchronously on mount, it will see `null`, redirecting the user to `/login`. Milliseconds later, Firebase confirms the session, redirecting back to `/dashboard`, creating the loop.

Unstable useEffect Dependencies

If your `useEffect` hook that handles the redirection depends on a user object that changes object reference on every render, it will trigger an infinite re-render loop.

useEffect(() => { if (!user) router.push('/login'); }, [user, router]); // if 'user' reference is unstable

Server-Side Rendering (SSR) Mismatches

In Next.js, the server renders the initial HTML without access to the user's IndexedDB. The server serves the 'logged-out' layout. Once the client hydrates, Firebase kicks in and updates to the 'logged-in' layout. Without a loading state, this causes a jarring layout shift and potential redirect loop.

Step-by-Step Fix Guide

1

Create an AuthContext with a Loading State

Wrap your application in a Context Provider that specifically tracks whether Firebase has completed its initial check.

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
      setLoading(false); // Crucial: Stop loading only after Firebase responds
    });
    return () => unsubscribe();
  }, []);

  return (
    <AuthContext.Provider value={{ user, loading }}>
      {children}
    </AuthContext.Provider>
  );
};
2

Block Routing While Loading

In your protected routes or higher-order components (HOCs), intercept the render if `loading` is true. Do not execute redirect logic.

const ProtectedRoute = ({ children }) => {
  const { user, loading } = useAuth();
  const router = useRouter();

  useEffect(() => {
    if (!loading && !user) {
      router.push('/login');
    }
  }, [user, loading, router]);

  if (loading) return <LoadingSpinner />; // Prevents the flash and redirect loop

  return user ? children : null;
};
3

Stabilize Object References

If you map the Firebase `User` object to a custom object, use `useMemo` to prevent the object reference from changing on every render, which would re-trigger `useEffect`.

  • Avoid deep object comparisons in `useEffect` arrays.
  • Rely on simple primitives if possible: `user?.uid` instead of the whole `user` object in the dependency array.

Caught in an Auth Loop?

Are your users stuck flickering between screens? Let me review your React/Next.js architecture and implement a production-grade auth state pattern.

Get Architecture Rescue

Related Errors

  • Error: Maximum update depth exceeded

    This React error accompanies the loop. Verify your `useEffect` dependencies are not causing state updates that trigger the effect again.

  • NextRouter was not mounted

    Occurs when redirecting before the Next.js router is fully ready. Ensure router usage is wrapped in `useEffect`.

Prevention Strategy

  • Always assume Firebase authentication is an asynchronous operation, even for returning users.
  • Never build a protected route system in React without a tri-state auth variable: `User Object`, `Null` (logged out), and `Undefined / Loading` (checking).

Still Stuck With This Issue?

Send your exact error message or deployment issue. I'll respond with a targeted fix.

Drop screenshots here or browse

PNG, JPG, WebP • Max 5MB • Up to 3 files

Private submission — your data is never shared publicly.

Need a Deeper Fix?

Describe your full project issue below and I'll get back to you with a targeted fix.

Drop screenshots here or browse

PNG, JPG, WebP • Max 5MB • Up to 3 files

Your data is stored securely and never shared with third parties.

Frequently Asked Questions about Stop Firebase Auth Infinite Redirect Loops in Next.js | Osmoutech

Why does my Next.js app flash the login screen before showing the dashboard?

Quick Answer: Because the server renders the login screen by default (as it has no access to client-side Firebase cookies). Use Next.js Middleware or `next-firebase-auth-edge` to pass the auth token to the server to render the correct UI instantly.

Is it safe to use Next.js Router inside onAuthStateChanged?

Quick Answer: It is better to manage state (user, loading) inside `onAuthStateChanged` and let a separate `useEffect` observing that state handle the Next.js routing. Mixing routing directly inside the Firebase callback often leads to race conditions.

ServicesStudent ProjectsBlogContact
Chat with an Expert