Next.js Redirect from / to another page

In next.js you can redirect after the page is loaded using Router ex :

import Router from 'next/router'

componentDidMount(){
    const {pathname} = Router
    if(pathname == '/' ){
       Router.push('/hello-nextjs')
    }
}

Or with Hooks :

import React, { useEffect } from "react";
import Router from 'next/router'

...
useEffect(() => {
   const {pathname} = Router
   if(pathname == '/' ){
       Router.push('/hello-nextjs')
   }
 });

There are three approaches.

1.Redirect on events or functions:

import Router from 'next/router';

<button type="button" onClick={() => Router.push('/myroute')} />

2.Redirect with hooks:

import Router , {useRouter}  from 'next/router';

const router = useRouter()

<button type="button" onClick={() => router.push('/myroute')} />

3.Redirect with Link:

based on Nextjs docs the <a> tag is neccessary inside the link for things like open in a new tab!

import Link from 'next/link';

<Link href="/myroute">
   <a>myroute</a>
</Link>

There are some other options for serverside routing which is asPath. in all described approaches you can add asPath to redirect both client and server side.


Next 9.4 answer

Hi, here is an example component working in all scenarios:

Vulcan next starter withPrivate access

Example usage here

The answer is massive, so sorry if I somehow break SO rules, but I don't want to paste a 180 lines piece of code. There is no easy pattern to handle redirection in Next, if you want to both support SSR and static export.

The following scenarios each need a specific pattern:

  • server side rendering: we render the page if allowed, HTTP redirect if not
  • static rendering (server-side): we render nothing, but we still include the page into the build
  • client side rendering, after a static export: we check client side if the user is auth, and redirect or not. We display nothing (or a loader) during this check or if we are redirecting.
  • client side rendering after a client redirect using next/router: same behaviour.
  • client side rendering after SSR: we use props passed by getInitialProps to tell if the user is allowed, directly at first render. It's just a bit faster, you avoid a blank flash.

At the time of writing (Next 9.4), you have to use getInitialProps, not getServerSideProps, otherwise you lose the ability to do next export.

Next 9.5 update

As stated by @Arthur in the comments, 9.5 also include the possibilities to setup redirects in next.config.js. The limitations of this feature are not yet clear to me, but they seem to be global redirections, e.g. when you need to move a page or to allow access only during a limited period. So they are not meant to handle authentication for instance, because they don't seem to have access to the request context. Again, to be confirmed.

Old answer (works, but will have a messy static render)

Semi-official example

The with-cookie-auth examples redirect in getInitialProps. I am not sure whether it's a valid pattern or not yet, but here's the code:

Profile.getInitialProps = async ctx => {
  const { token } = nextCookie(ctx)
  const apiUrl = getHost(ctx.req) + '/api/profile'

  const redirectOnError = () =>
    typeof window !== 'undefined'
      ? Router.push('/login')
      : ctx.res.writeHead(302, { Location: '/login' }).end()

  try {
    const response = await fetch(apiUrl, {
      credentials: 'include',
      headers: {
        Authorization: JSON.stringify({ token }),
      },
    })

    if (response.ok) {
      const js = await response.json()
      console.log('js', js)
      return js
    } else {
      // https://github.com/developit/unfetch#caveats
      return await redirectOnError()
    }
  } catch (error) {
    // Implementation or Network error
    return redirectOnError()
  }
}

It handles both server side and client side. The fetch call is the one that actually get the auth token, you might want to encapsulate this into a separate function.

What I would advise instead

 1. Redirect on server-side render (avoid flash during SSR)

This is the most common case. You want to redirect at this point to avoid the initial page flashing on first load.

MyApp.getInitialProps = async appContext => {
    const currentUser = await getCurrentUser(); // define this beforehand
    const appProps = await App.getInitialProps(appContext);
    // check that we are in SSR mode (NOT static and NOT client-side)
    if (typeof window === "undefined" && appContext.ctx.res.writeHead) {
      if (!currentUser && !isPublicRoute(appContext.router.pathname)) {
          appContext.ctx.res.writeHead(302, { Location: "/account/login" });
          appContext.ctx.res.end();
      }
    }
    return { ...appProps, currentUser };
  };
 2. Redirect in componentDidMount (useful when SSR is disabled, eg in static mode)

This is a fallback for client side rendering.

  componentDidMount() {
    const { currentUser, router } = this.props;
    if (!currentUser && !isPublicRoute(router.pathname)) {
      Router.push("/account/login");
    }
  }

I could not avoid flashing the initial page in static mode add this point, because you can't redirect during the static build, but it seems better than the usual approaches. I'll try to edit as I make progress.

Full example is here

Relevant issue, which sadly ends up with a client only answer

New issue I've opened regarding redirecton