Blank page after router.push() in Next.js?

By

How to fix the blank page you get after calling router.push() in Next.js: stop returning it from render, call it in useEffect or use redirect() instead.

~~~

When working in Next.js, a blank page after you programmatically call router.push() usually means you used it as a return value. The fix is to call router.push() on its own line, and nothing else.

I had this problem too, and here’s how I solved it.

Why does this happen?

router.push() does not return JSX. In the App Router (useRouter from next/navigation) it returns nothing at all, so you get undefined. In the Pages Router (next/router) it returns a promise.

If your component returns either of those, React has nothing to render. You get a blank page.

So don’t do this:

router.push('/')
return

And don’t do this:

return router.push('/')

Do this:

router.push('/')

Where the problem usually hides

The typical case is a redirect inside the component body. You check some condition, and if it fails, you send the user somewhere else:

'use client'

import { useRouter } from 'next/navigation'

export default function Dashboard({ user }) {
  const router = useRouter()

  if (!user) {
    return router.push('/login')
  }

  return <p>Welcome back</p>
}

This looks reasonable, but the component now returns undefined (or a promise, on the Pages Router) instead of JSX. Blank page.

Also, changing the route is a side effect. Side effects don’t belong in the render phase.

How to fix it (App Router)

In a Client Component, move the redirect into a useEffect() hook, and return null while the navigation happens:

'use client'

import { useRouter } from 'next/navigation'
import { useEffect } from 'react'

export default function Dashboard({ user }) {
  const router = useRouter()

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

  if (!user) return null

  return <p>Welcome back</p>
}

The effect runs after the render, calls router.push() on its own line, and React renders null in the meantime.

On the server, prefer redirect() from next/navigation inside a Server Component or Server Action instead of useRouter. That matches the pattern in how to programmatically change a route in Next.js.

Inside event handlers you don’t need any of this. A click handler is not a render, so calling it there is fine:

const handleLogout = () => {
  router.push('/login')
}

Notice there’s still no return in front of it.

Pages Router (older apps)

If your app still uses pages/, the same bug and fix apply with useRouter from next/router:

import { useRouter } from 'next/router'
import { useEffect } from 'react'

export default function Dashboard({ user }) {
  const router = useRouter()

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

  if (!user) return null

  return <p>Welcome back</p>
}

One more thing to watch for

If you skip the if (!user) return null line, the component renders its content once before the redirect completes.

The user sees a flash of the protected page, then the login page. Returning null (or a loading message) while redirecting avoids that.

Tagged: Next.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about next: