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 using return with it, just call router.push() on its own line and nothing else.

~~~

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. It returns a promise.

If your component returns that promise, 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:

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 a promise 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

Move the redirect into a useEffect() hook, and return null while the navigation happens:

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>
}

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

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.

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
~~~

Related posts about next: