Guide to forwarding a visitor from an outdated URL to a fresh one, complete with slug using Next.js redirect 301

I made a change to the URL of one of my subpages that is already live. The old link is no longer supported, but it is still present in many places. Instead of updating all instances of the old link, I would like to set up a redirect from the old URL to the new one. I came across Next.js Redirects as a possible solution, but I am encountering issues with its implementation.

The original URL was:

http://localhost:3000/product/id

The new URL now looks like this:

http://localhost:3000/product/SLUG-id

My API fetches data based solely on the ID in getServerSideProps. Previously, the slug was separated from the ID.

export const getServerSideProps = async (context: any) => {
    const slugId = context.params.slugId;
    const id = slugId.split('-').pop();

    const apolloClient = initializeApollo(context);
    const { data } = await apolloClient.query({
        query: GET_PRODUCTS,
        variables: {
            id,
        },
    });
    return {
        props: {
            data,
        },
    };
};

The new flow of the page includes passing the slug when navigating to the product subpage:

<Link href={`/product/${product.slug}-${productId}`}>

The old link contains an ID but lacks a slug component.

When my next config is set as follows, I encounter an error:

module.exports = {
    nextConfig,
    async redirects() {
        return [
            {
                source: '/product/:slug',
                destination: '/product/:slugId',
                permanent: true,
            },
        ];
    },
};

Editing the next config led to an error:

warn  - Invalid next.config.js options detected:
  - The root value has an unexpected property, nextConfig, which is not in the list of allowed properties (amp, analyticsId, assetPrefix, basePath, cleanDistDir, compiler, compress, crossOrigin, devIndicators, distDir, env, eslint, excludeDefaultMomentLocales, experimental, exportPathMap, future, generateBuildId, generateEtags, headers, httpAgentOptions, i18n, images, onDemandEntries, optimizeFonts, output, outputFileTracing, pageExtensions, poweredByHeader, productionBrowserSourceMaps, publicRuntimeConfig, reactStrictMode, redirects, rewrites, sassOptions, serverRuntimeConfig, staticPageGenerationTimeout, swcMinify, trailingSlash, typescript, useFileSystemPublicRoutes, webpack).

See more info here: https://nextjs.org/docs/messages/invalid-next-config
`destination` has segments not in `source` or `has` (slugId) for route {"source":"/product/:slug","destination":"/product/:slugId","permanent":false}


Error: Invalid redirect found

Can I successfully redirect users from the old link to the new one while including the slug in the URL? It seems like getServerSideProps can handle this URL structure and retrieve the necessary data even without the slug in the link, although having the slug included is important for SEO purposes.

Preferred scenario:

User clicks on the old link and is directed to the designated page seamlessly. Data is fetched correctly, and the URL displays the slug-id format, even though only the ID is required for data retrieval.

Answer №1

To ensure that Next.js can access the keys within nextConfig, it is necessary to spread the nextConfig key.

The updated code should look like this:

module.exports = {
    ...nextConfig,
    async redirects() {
        return [
            {
                source: '/product/:slug',
                destination: '/product/:slugId',
                permanent: true,
            },
        ];
    },
};

Alternatively, you can simply include the async redirects() {... function inside the nextConfig object.

Check out the Spread documentation for more information

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to use hooks in NETXJS to pass data from a page to a component

Hey there, how are you doing? I am currently working on a project using Next.js and styled components. I am trying to change a string using props in my layout component, where the main content is dynamic per page. Page 'prueba.js' import React f ...

Leveraging import and export functionality in TypeScript while utilizing RequireJS as a dependency

I am in the process of transitioning a complex JavaScript application from Backbone/Marionette to TypeScript. While making this shift, I want to explore the benefits of exporting and importing classes using files as modules. Is it necessary to incorporat ...

What is the correct way to define elements and event targets in TypeScript?

Why is it possible to do this in TypeScript: const element: HTMLInputElement = document.querySelector('input'); However, doing this does not work: const element: HTMLInputElement = event.target; My understanding is that HTMLInputElement is a su ...

Specify the object key type when using a `for-in` loop

My current situation involves an object type: interface ShortUrlParam { openid: string; avatar: string; nickname: string; } const param: ShortUrlParam = { openid: 'abc123', avatar: '', nickname: 'wenzi&apo ...

Trouble with loading images when navigating to a new page with NextJS Link component

Explaining this issue thoroughly would require sharing my entire project, but here's a brief overview. I suspect the problem lies within using a combination of getInitialProps() and getStaticProps(). When navigating between pages using next/link, imag ...

What could be causing the type error in Vue 3.3 when using a generic v-for key?

My application is built on Vue 3.3.4 with the latest support for generics in single file components. One of the components I'm working on is a generic list, which iterates over a set of items passed as a prop. There is also a prop called itemKey, used ...

The interconnectivity between ngAfterViewInit in Angular's LifeCycle and observables

enable.service.ts @Injectable({ providedIn: 'root' }) export class EnableService { isEnabled$ = from(this.client.init()).pipe( switchMap(() => this.client.getEnabled()), map(([enabled, isAdmin]) => ({enabled: true, isAdmin: fals ...

What external libraries does Angular 4 utilize during execution, aside from RxJS?

Angular 4 relies on RxJS types in its public API and also internally depends on RxJS. It would be beneficial to explore if Angular utilizes other external packages for certain functionalities, allowing us to incorporate them into our own projects. This ap ...

Tips on effectively transferring formarray to another component

I'm attempting to pass a formarray to a child component in order to display the values within the formarray there. Here is my current code, but I am struggling to figure out how to show the formarray values in the child component. app.component.html ...

Encountered a syntax issue within the library code while integrating Material Design with Rails, Webpacker, Typescript, and Angular

I am facing a syntax error in my Rails application, specifically in a large JS file that seems to be generated by webpacker. The error appears to be related to Angular/Material code. Interestingly, when I exclude material design, the error disappears. Here ...

Having trouble changing file names in a Next.js 13 project

I've been facing an issue ever since Next.Js 13 updated the `pages` folder to a new `app` folder. Whenever I try to rename the default "Pages.tsx" file to something like "Home.tsx" or "Information.tsx", it breaks and shows a 404 Page error. The first ...

Exploring Next.js dynamic imports using object destructuring

import { UDFCompatibleDatafeed } from "./datafeeds/udf/src/udf-compatible-datafeed.js"; I'm facing a challenge in converting the above import to a dynamic import in Next.js. My attempt was as follows: const UDFCompatibleDatafeed = dynamic(( ...

When navigating to a deep link or refreshing the page, NextJS fails to maintain global variables from the script

Within my Pages/_document.tsx file, there is a script that loads global public configuration as shown below. This script assigns global variables to the window object. Interestingly, when I initially load the home route of my application, everything work ...

Ways to achieve the organization of nested promises in Angular 9

I am facing an issue with the order of asynchronous calls in my Angular script. Despite having multiple nested async calls, the order of execution seems to be disrupted. Here is a snippet of my Angular code: saveArticles(articles, action) { articles.f ...

Discovering routes in Angular2

I'm attempting to replicate something similar to this example here: AngularJS show div based on url/condition <span id="page-locator" *ngIf="location.path() == '/overview'">test</span> Unfortunately, it's not working as ex ...

The process of verifying email addresses using Angular 5

I'm having trouble validating my email with the .com domain. I've tried various methods, but so far, none have worked. Can anyone provide guidance? I'm new to Angular and struggling with this particular issue. Ideally, I want the email to be ...

There is a WARNING occurring at line 493 in the file coreui-angular.js located in the node_modules folder. The warning states that the export 'ɵɵdefineInjectable' was not found in the '@angular/core' module

I encountered a warning message while running the ng serve command, causing the web page to display nothing. Our project utilizes the Core Ui Pro Admin Template. Here is the list of warning messages: WARNING in ./node_modules/@coreui/angular/fesm5/coreu ...

Error code 2532 occurs when trying to access an object using square brackets in TypeScript

Encountered the ts error: Object is possibly 'undefined'.(2532) issue while trying to access the value of a field within an object, where the object key corresponds to a value in an Enum. Below is a concise example to showcase this problem: en ...

How can we ensure that only one of two props is specified during compilation?

I've designed a customized Button component. interface Button { href?: string; action(): void; } I'm looking to ensure that when a consumer uses this Button, they can only pass either href or action as a prop, not both. I want TypeScri ...

Typescript: Verifying if a parameter matches a specific type

Here are my constructor implementations: constructor(position: FlagPosition, flag: string); constructor(position: FlagPosition, flag: Expression<any> | string) { this.position = position; //TODO: Check if flag type is a string or an Expressi ...