Next.js Redirect from / to another page
Asked Answered
C

19

198

I'm new in Next.js and I'm wondering how to redirect from start page ( / ) to /hello-nextjs for example. Once user loads a page and after that determine if path === / redirect to /hello-nextjs

In react-router we do something like:

<Switch>
  <Route path="/hello-nextjs" exact component={HelloNextjs} />
  <Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
Cockatiel answered 30/9, 2019 at 19:1 Comment(2)
when you want that the redirect happens?Prosthodontics
import { useRouter } from "next/navigation"; router.push("/");Weariless
B
81

Update 2024 App Router: the currently most voted answer above is more up-to-date than this one.

Caveat

First, you should asses whether you need client-side redirection (within React), server-side redirection (301 HTTP response) or server-side redirection + authentication (301 HTTP response but also having some logic to check authentication).

This is the most complete answer I could write. But, in most scenarios, you do not need any of this. Just redirect as you would do in any React app. Prefer client-side redirections first. Just using useEffect + router.push, and that's it.

Server-side redirection are tempting, in particular when you want to "secure" private pages, but you should assess whether you really need them. Usually, you don't. They induce unexpected complexity, like managing auth token and refresh token. Instead, you may want to add a gateway server, a reverse proxy or whatever upfront server to your architecture for instance to handle those kind of checks.

Keep in mind that Next.js are just React app, and using Next.js advanced features like SSR comes at a cost that should be justified in your context.

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.

Next 10 new doc update

This solution is specific to redirection depending on authentication.

Authentication patterns are now documented

I am not fond of authenticated from getServerSideProps, because it's in my opinion quite too late and can be difficult to set up with advanced patterns such as handling refresh token. But that's the official solution.

You may also want to check the approach documented in this ticket based on how Vercel's dashboard works (at the time of writing), that prevents flash of unauthenticated content

Next 10.2 header and cookies based rewrites update

Next 10.2 introduces Rewrites based on headers and cookies. That's a great way to redirect server-side, based on the presence of an authentication cookie or header.

However, keep in mind that this is not a secure redirection. User can alter their request headers with a false token. You still need a gateway, a reverse proxy or an upfront server to actually check token validity and correctly set the headers.

Edit: note that the URL won't change. A rewrite points an URL to an existing page of your application, without changing the URL => it allows you to have "virtual" URLs.

Example use case: imagine you have a page src/contact.tsx, that is translated, and i18n redirection setup. You can translate the page name itself ("contact") by rewriting /de/kontact to /de/contact.

Next 12 update

Now middlewares gives you full-control on server-side redirects.

However, keep in mind again, that most of the time a client-side redirect and check is just enough.


Outdated Next 9.4 answer (links are dead sorry)

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.

Even more outdated 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

Boser answered 10/3, 2020 at 11:17 Comment(5)
In v9.5.0 it is possible to add redirects to next.config.js - link. This way you can update your answer if it is relevant informationCockatiel
Thanks! Documentation is not completely clear about the context in which redirects can be used: does it work in "export" mode, do you have access to the request object during SSR? As far as I understand those are global redirects, like you moved a route, or you have a page available for a limited amount of type, that for every users. Would need more testing/more feedback to update my answer.Boser
Smells like your are redirect also from the /login page so you get an infinite loop.Boser
these links are dead Vulcan next starter withPrivate access Example usage hereWorkingman
They are definitely outdated anyway. Edited the post to reflect that.Boser
P
339

Update: Next.js >= 13 with AppDir enabled
You can use next/navigation to redirect both in client components and server components.

Ex. in pages :

import { redirect } from 'next/navigation';
export default async function Home({ params }) {
    redirect('/hello-nextjs');
  // ...
}

Ex. In client components:

'use client';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

export const Home= () => {
  const { push } = useRouter();

  useEffect(() => {
     push('/hello-nextjs');
  }, []);
  return <p></p>;
};

Update: Next.js >= 12.1
As @warfield pointed out in his answer from next.js >= 12.1 relative URLs are no longer allowed in redirects and using them will throw an error. I'm reposting here his answer for more visibility :

To redirect using middleware with Next.js >= 12.1:

  1. Create a middleware.ts (or .js) file at the same level as your pages directory
  2. Export a middleware function
  3. Create an absolute URL and pass it to redirect

TypeScript example middleware.ts:


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {   
  const url = request.nextUrl.clone()   
  if (url.pathname === '/') {
    url.pathname = '/hello-nextjs'
    return NextResponse.redirect(url)   
  } 
}

Update: Next.js >= 12
Now you can do redirects using middleware, create a _middleware.js file inside the pages folder (or any sub folder inside pages)

import { NextResponse, NextRequest } from 'next/server'
export async function middleware(req, ev) {
    const { pathname } = req.nextUrl
    if (pathname == '/') {
        return NextResponse.redirect('/hello-nextjs')
    }
    return NextResponse.next()
}

Update: Next.js >= 10

From Next.js 10 you can do server side redirects (see below for client side redirects) with a redirect key inside getServerSideProps or getStaticProps :

export async function getServerSideProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  // or use context.resolvedUrl for conditional redirect
  // if(context.resolvedUrl == "/")
  if (!data) {
    return {
      redirect: {
        destination: '/hello-nextjs',
        permanent: false,
      },
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

Note : Using getServerSideProps will force the app to SSR,also redirecting at build-time is not supported , If the redirects are known at build-time you can add those inside next.config.js

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')
   }
 });

If you want to prevent the flashing before the redirect you can use a simple trick :

import React, { useEffect,useState } from "react";
import Router from 'next/router'
const myPage = ()=>{
    const [loaded,setLoaded] = useState(false)
    useEffect(() => {
        const {pathname} = Router
        // conditional redirect
        if(pathname == '/' ){
            // with router.push the page may be added to history
            // the browser on history back will  go back to this page and then forward again to the redirected page
            // you can prevent this behaviour using location.replace
            Router.push('/hello-nextjs')
           //location.replace("/hello-nextjs")
        }else{
            setLoaded(true)
        }
      },[]);

    if(!loaded){
        return <div></div> //show nothing or a loader
    }
    return ( 
        <p>
            You will see this page only if pathname !== "/" , <br/>
        </p> 
    )
}
export default myPage

I would say that in general is not a good/elegant approach to do client redirects when you can use next.config.js redirects or even better use conditional render of components.

I have create a simple repo with all the examples above here.

Prosthodontics answered 1/10, 2019 at 10:15 Comment(15)
How do I do with React hooks??Abscind
Without using the classesAbscind
What about SSR? The initial page is flashing with this approachBoser
@EricBurel the OP clearly asked "Once user loads a page" btw check this github.com/zeit/next.js/issues/649Prosthodontics
Agreed the question is not completely clear about what "once the page is loaded means". When using React-Router, SSR is handled out-of-the-box so you don't have a difference between client and server.Boser
Is _middleware also available when self hosting, because the middleware functions normally gets deployed as edge functions.Phelloderm
@Phelloderm yes it is, edge functions are just middlewares but in the edgeProsthodontics
When I for example host the web app in a VPS would these functions in the _middleware then just get run locally?Phelloderm
Heads up _middleware is still in Beta (yes, deployed as Edge Functions) which tend to throw errors when launched to Vercel anyway.Niue
middlewares still beta versionGrunter
next-auth.js.org/getting-started/client#getsession was helpful for me.Streptomycin
Answer throws Error: URLs is malformed for Next.js >= 12.1 because relative URLs can no longer be used. Updated version of Nico's answer using absolute URLs + link to docs here: stackoverflow.com/a/73711454Toluidine
302 redirect possible in SSG? For example, is there a known way to use fallback: true in getStaticPaths() and then somehow return a 302 redirect on a previously-not-rendered static path after all? When I try to return the redirect key from getStaticProps(), it complains with nextjs.org/docs/messages/gsp-redirect-during-prerenderPerseverance
On Next.js >= 13 with AppDir enabled, is there a way to return a 301 redirect (permanent) instead of 302 (temporary) from the server side? I couldn't find an answer in the docs.District
I'm having trouble with Next.js >= 13, expressly 13.4.2. I'm on the client side trying to use the import { redirect } from 'next/navigation'. Whenever I call the redirect function I get Error: NEXT_REDIRECT. Can someone help me out?Ultrasonic
B
81

Update 2024 App Router: the currently most voted answer above is more up-to-date than this one.

Caveat

First, you should asses whether you need client-side redirection (within React), server-side redirection (301 HTTP response) or server-side redirection + authentication (301 HTTP response but also having some logic to check authentication).

This is the most complete answer I could write. But, in most scenarios, you do not need any of this. Just redirect as you would do in any React app. Prefer client-side redirections first. Just using useEffect + router.push, and that's it.

Server-side redirection are tempting, in particular when you want to "secure" private pages, but you should assess whether you really need them. Usually, you don't. They induce unexpected complexity, like managing auth token and refresh token. Instead, you may want to add a gateway server, a reverse proxy or whatever upfront server to your architecture for instance to handle those kind of checks.

Keep in mind that Next.js are just React app, and using Next.js advanced features like SSR comes at a cost that should be justified in your context.

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.

Next 10 new doc update

This solution is specific to redirection depending on authentication.

Authentication patterns are now documented

I am not fond of authenticated from getServerSideProps, because it's in my opinion quite too late and can be difficult to set up with advanced patterns such as handling refresh token. But that's the official solution.

You may also want to check the approach documented in this ticket based on how Vercel's dashboard works (at the time of writing), that prevents flash of unauthenticated content

Next 10.2 header and cookies based rewrites update

Next 10.2 introduces Rewrites based on headers and cookies. That's a great way to redirect server-side, based on the presence of an authentication cookie or header.

However, keep in mind that this is not a secure redirection. User can alter their request headers with a false token. You still need a gateway, a reverse proxy or an upfront server to actually check token validity and correctly set the headers.

Edit: note that the URL won't change. A rewrite points an URL to an existing page of your application, without changing the URL => it allows you to have "virtual" URLs.

Example use case: imagine you have a page src/contact.tsx, that is translated, and i18n redirection setup. You can translate the page name itself ("contact") by rewriting /de/kontact to /de/contact.

Next 12 update

Now middlewares gives you full-control on server-side redirects.

However, keep in mind again, that most of the time a client-side redirect and check is just enough.


Outdated Next 9.4 answer (links are dead sorry)

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.

Even more outdated 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

Boser answered 10/3, 2020 at 11:17 Comment(5)
In v9.5.0 it is possible to add redirects to next.config.js - link. This way you can update your answer if it is relevant informationCockatiel
Thanks! Documentation is not completely clear about the context in which redirects can be used: does it work in "export" mode, do you have access to the request object during SSR? As far as I understand those are global redirects, like you moved a route, or you have a page available for a limited amount of type, that for every users. Would need more testing/more feedback to update my answer.Boser
Smells like your are redirect also from the /login page so you get an infinite loop.Boser
these links are dead Vulcan next starter withPrivate access Example usage hereWorkingman
They are definitely outdated anyway. Edited the post to reflect that.Boser
T
69

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.

Edit 13.12.2022

1.Redirect with Link doesn't require anchor tag anymore!

import Link from 'next/link';

<Link href="/myroute">
  my route
</Link>

2.Use Nextj.js Redirects

in next.config.js

module.exports = {
  async redirects() {
    return [
      {
        source: '/someroute',
        destination: '/myroute',
        permanent: true,
      },
    ]
  },
}
Trinitytrinket answered 1/10, 2019 at 17:46 Comment(3)
This is an imperative approach. It's ok to redirect on user action but not based on a condition on page load as stated in the question.Boser
I didn't get what you meant!?Trinitytrinket
The question is about automatically redirecting depending on the current route pathname. Your answers are valid but not appliable in this context: they all require a user click.Boser
L
21

Next.js 10+ is offering us some extra and elegant solution to make a redirection.

  1. SERVER-SIDE - you should use getServerSideProps

    The example below assume that we have some extra session to check (but can be anything that you want). If the session is empty and we are on the server-side (context.res), that's mean that the user is not logged in and we should redirect to the login page (/login).. In another way we can pass session to props and redirect to the /dashboard:

    import { getSession } from 'next-auth/client';
    
    export const getServerSideProps = async (context) => {
      const session = await getSession(context);
      if(context.res && !session) {
        return {
          redirect: {
            permanent: false,
            destination: '/login'
          }
        }
      }
    
      return {
        props: { session },
        redirect: {
          permanent: false,
          destination: '/dashboard'
        }
      }
    }
    
    
  2. CLIENT-SIDE - you can use for example useRouter hook:

    import { useRouter } from 'next/router';
    import { useSession } from 'next-auth/client';   
    
    const router = useRouter();
    const [ session, loading ] = useSession();
    
    if (typeof window !== 'undefined' && loading) return null;
    
    if (typeof window !== 'undefined' && !session) {
      router.push('/login');
    }
    
    router.push('/dashboard');
    

More info here: https://github.com/vercel/next.js/discussions/14890

Leery answered 23/1, 2021 at 21:4 Comment(2)
Where do useRouter and useSession come from?Pugnacious
implementation of nextjsGrunter
T
13

Here are 2 copy-paste-level examples: one for the Browser and one for the Server.

https://dev.to/justincy/client-side-and-server-side-redirection-in-next-js-3ile

Let's say you want to redirect from your root (/) to a page called home: (/home)

In your main index file, paste this:

Client Side

import { useRouter } from 'next/router'

function RedirectPage() {
  const router = useRouter()
  // Make sure we're in the browser
  if (typeof window !== 'undefined') {
    router.push('/home')
  }
}

export default RedirectPage

Server Side

import { useRouter } from 'next/router'

function RedirectPage({ ctx }) {
  const router = useRouter()
  // Make sure we're in the browser
  if (typeof window !== 'undefined') {
    router.push('/home');
    return; 
  }
}

RedirectPage.getInitialProps = ctx => {
  // We check for ctx.res to make sure we're on the server.
  if (ctx.res) {
    ctx.res.writeHead(302, { Location: '/home' });
    ctx.res.end();
  }
  return { };
}

export default RedirectPage
Taraxacum answered 6/8, 2020 at 6:59 Comment(2)
Thanks. The explanations about Client-Side and Server-Side Redirects in Next.js, plus HOC abstraction given in this article are really valuable !Foggy
So far the best answer, with the most correct client side router implementation. All the others use the hook wrong, or don't even use useRouter() at all.Companionable
A
12

Valid for NextJS 9.5.0+

  1. Create next.config.js file
  2. add source and destination url (you can set to permanent redirect if external domain)
module.exports = {
  async redirects() {
    return [
      {
        source: '/team',
        destination: '/about',
        permanent: false,
      },
      {
        source: "/blog",
        destination:
          "https://blog.dundermifflin.com",
        permanent: true,
      },
    ];
  },
};


https://github.com/vercel/next.js/tree/canary/examples/redirects

Architrave answered 4/10, 2020 at 18:20 Comment(1)
May I know what is the difference between permanent redirect and non-permanent redirect? I can't get the idea of a non-permanent redirect.Gantlet
A
8

@Nico's answer solves the issue when you are using classes.

If you are using function you cannot use componentDidMount. Instead you can use React Hooks useEffect .


import React, {useEffect} from 'react';

export default function App() {
  const classes = useStyles();

  useEffect(() => { 
    const {pathname} = Router
    if(pathname == '/' ){
      Router.push('/templates/mainpage1')
    }  
  }
  , []);
  return (
    null
  )
}

In 2019 React introduced hooks. which are much faster and efficient than classes.

Abscind answered 3/2, 2020 at 11:52 Comment(4)
This issue describes what I wanted as a resultCockatiel
@Cockatiel . Oh, but your question does not say so. The answer by @Prosthodontics and mine are exactly same and is a substitute for the <Switch> that you are using in React-router. Even <Switch> does not provide any 303, 302 status code. Just redirectsAbscind
Well, I think the discussed here too. Just realised that NextJS does not set any status code. github.com/zeit/next.js/issues/9443Abscind
Please remove classes. It is of no use here.Lsd
L
7

In NextJs v9.5 and above you can configure redirects and rewrites in the next.config.js file.

But if you are using trailingSlash: true ensure that the source path ends with a slash for proper matching.

module.exports = {
  trailingSlash: true,
  async redirects() {
    return [
      {
        source: '/old/:slug/', // Notice the slash at the end
        destination: '/new/:slug',
        permanent: false,
      },
    ]
  },
}

You also need to account for other plugins and configurations that may affect routing, for example next-images.

Documentation: https://nextjs.org/docs/api-reference/next.config.js/redirects

Lavonia answered 22/4, 2021 at 12:45 Comment(1)
Thank you very much for the hint with the trailing slash!Chavis
C
6

redirect-to.ts

import Router from "next/router";

export default function redirectTo(
  destination: any,
  { res, status }: any = {}
): void {
  if (res) {
    res.writeHead(status || 302, { Location: destination });
    res.end();
  } else if (destination[0] === "/" && destination[1] !== "/") {
    Router.push(destination);
  } else {
    window.location = destination;
  }
}

_app.tsx

import App, {AppContext} from 'next/app'
import Router from "next/router"
import React from 'react'
import redirectTo from "../utils/redirect-to"


export default class MyApp extends App {
  public static async getInitialProps({Component, ctx}: AppContext): Promise<{pageProps: {}}> {
    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    if (ctx.pathname === "" || ctx.pathname === "/_error") {
      redirectTo("/hello-next-js", { res: ctx.res, status: 301 }); <== Redirect-To
      return {pageProps};
    }

    return {pageProps};
  }

  render() {
    const {Component, pageProps} = this.props;
    return <Component {...pageProps}/>
  }
}
Cockatiel answered 3/10, 2019 at 20:9 Comment(3)
This shouldn't be the accepted answer. According to this github.com/zeit/next.js/issues/4931#issuecomment-512787861 you should not redirect in getInitialProps. @Trinitytrinket should be the accepted answer. And also you are using next.js you don't need react router to organize routes. Next already handles that by default.Zabrine
@rotimi-best, as far as I remember, I took this code from the next.js example. Also, I did not use a react-router, it was presented as an example of what I wanted to getCockatiel
This is a valid answer but with SSR only. It will not redirect in static apps. Edit: actually it will you added Router.push, however the client-side Router.push should go into the component lifecycle methods insteadBoser
M
5

I have implemented this functionality in my Next.JS app by defining a root page this does the redirect server side and client side. Here is the code for the root page:

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

const redirectTo = "/hello-nextjs";

const RootPage = () => {
  useEffect(() => Router.push(redirectTo));
  return null;
};
RootPage.getInitialProps = (ctx) => {
  if (ctx.req) {
    ctx.res.writeHead(302, { Location: redirectTo });
    ctx.res.end();
  }
};

export default RootPage;
Mccreery answered 20/4, 2020 at 17:10 Comment(1)
It will most probably fail static export though, because ctx.res.writeHead is not defined in this context.Boser
T
5

Next.js >= 12.1

Relative URLs are no longer allowed in redirects and will throw:
Error: URLs is malformed. Please use only absolute URLs.

To redirect using middleware with Next.js >= 12.1:

  1. Create a middleware.ts (or .js) file at the same level as your pages directory
  2. Export a middleware function
  3. Create an absolute URL and pass it to redirect

TypeScript example middleware.ts:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const url = request.nextUrl.clone()
  if (url.pathname === '/') {
    url.pathname = '/hello-nextjs'
    return NextResponse.redirect(url)
  }
}

Toluidine answered 14/9, 2022 at 4:15 Comment(1)
I'm trying to implement a success page redirect after sign up and this worked best for my case.Beery
T
4

🤷‍♂️ useEffect will redirect but jump immediately back to current page

useLayoutEffect works like a charm:

const router = useRouter();

useLayoutEffect(() => {
  router.isFallback && router.replace("/course");
}, [router]);

ℹ️ I've used the same code above for useEffect.

Tautologize answered 23/5, 2022 at 4:4 Comment(0)
T
3

If your intention is to ensure your app is running like a SPA and wanting to intercept an incoming invalid (or valid) pathname, which the user pasted into the address bar, then here's a fast/hacky way to do that.

Assume your paths are,

enum ERoutes {
  HOME = '/',
  ABOUT = '/about',
  CONTACT = '/contact'
}

Add a custom _error page if you don't have one already, and add this to it:

import React from 'react';
import { NextPage } from 'next';
import { useDispatch } from 'react-redux';
import { useRouter } from 'next/router';

const Error: NextPage = () => {
    const { asPath, push } = useRouter();
    const dispatch = useDispatch();

    React.useEffect(() => {
        const routeValid = Object.values(ERoutes).includes(asPath);

        if (routeValid) {
          // do some stuff, such as assigning redux state to then render SPA content in your index page
        } else {
          // you can either continue to render this _error component, or redirect to your index page,
          // where you may have your own error component that is displayed based on your app state.
          // In my case, I always redirect to '/' (as you can see below, where I push('/'), but before doing so,
          // I dispatch relevant redux actions based on the situation
        }

        // I redirect to root always, but you can redirect only if routeValid === true
        push('/');
    }, []);

    return (
        <div>Error because '{asPath}' does not exist</div>
    );
};

export default Error;
Targum answered 18/8, 2020 at 9:25 Comment(0)
B
3

Redirects Starting from Next.js 9.5 you are now able to create a list of redirects in next.config.js under the redirects key:

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
    ];
  },
};

Ofiicial Docs

Banks answered 26/9, 2022 at 8:47 Comment(0)
Z
2

This is what worked for me. Next.js >= 13.2 with appDir disabled.

If you want to redirect and mutate the URL (i.e. the browser changes from / -> /hello-nextjs). Create a file called middleware.ts (or middleware.js) and place it in the folder where your pages directory is. e.g. my pages is located in /src/pages, so we will get /src/middleware.ts.

export default async function middleware(req: NextRequest) {
    const { pathname } = req.nextUrl;
    if (pathname === "/") {
        // Redirect from /-> /hello-nextjs
        return NextResponse.redirect(new URL("/hello-nextjs", req.nextUrl));
    }
    return NextResponse.next();
}

Notes:

  1. Relative URLs do not work with Next.js >=13.2 and thus why we need to mutate the existing URL as seen above. (source: middleware-relative-urls)
  2. If you don't mind the URL remaining the same, but still redirecting (i.e. / redirects to /hello-nextjs, but the browser URL remains as /, you can use NextResponse.rewrite() instead of NextResponse.redirect().
Zohar answered 21/3, 2023 at 23:7 Comment(0)
A
1

Here's the middleware solution to avoid URLs is malformed. Please use only absolute URLs error.

Also, using paths object may be the cleaner way to handle redirection.

// pages/_middleware.ts

import { NextRequest, NextResponse } from 'next/server';

export async function middleware(req: NextRequest) {
  const { pathname, origin } = req.nextUrl;

  const paths: { [key: string]: string } = {
    '/admin/appearance': `${origin}/admin/appearance/theme`,
  };

  const rePath = paths[pathname];
  if (rePath) return NextResponse.redirect(rePath);
  else return NextResponse.next();
}
Amsden answered 19/4, 2022 at 2:4 Comment(0)
A
1

In Next.js, you can achieve redirection using the useEffect() hook in combination with the useRouter() hook. The useEffect() hook will be used to perform the redirection after the page is loaded, and the useRouter() hook allows you to access the current route information.

Here's an example of how you can redirect from the start page (path "/") to "/hello-nextjs" in Next.js:

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

const Home = () => {
  const router = useRouter();

  useEffect(() => {
    // Check if the current path is "/"
    if (router.pathname === "/") {
      // Redirect to "/hello-nextjs"
      router.push("/hello-nextjs");
    }
  }, [router]);

  return (
    <div>
      {/* Your home page content goes here */}
    </div>
  );
};
export default Home;
Acaudal answered 21/7, 2023 at 8:32 Comment(0)
E
0

You can set a base path. Next Js allows you to do this. For example, to use /login instead of / (the default), open next.config.js and add the basePath config:

  const nextConfig = {
  basePath: "/login",
};

module.exports = nextConfig;

You can also check out their docs here https://nextjs.org/docs/api-reference/next.config.js/basepath

Eire answered 31/8, 2022 at 13:48 Comment(0)
A
0
import Link from "next/link";

const Header = () => {

    return (
        <div>
            <nav>
                <ul>
                    <li> <Link href='/home'>Home </Link></li>
                    <li> <Link href='/about'>About </Link></li>
                    <li> <Link href='/contact'>Contact US </Link></li>
                </ul>
            </nav>
        </div>
    );
};
export default Header;
Acinus answered 1/12, 2023 at 12:14 Comment(1)
There are many other (and older) answers to this question already. While we welcome new solutions, it would be better if you explain how and why yours is better than (or, at least, different from) others.Rataplan

© 2022 - 2024 — McMap. All rights reserved.