Chris.luChris.lu header image, displaying an 80s style landscape and sunset

Next.js configuration

In this part, we will learn about config phases and tweak the react strict mode as well as the powered by header configuration

3 ways to know what the current environment is

To be able to know what the current environment is, you could use the Node.js NODE_ENV environment variable from process.env

However, you need to know that this variable will only ever have two states, when using the npm run dev command (the start dev server command) then this variable is development, when using the npm run build command (the build command) Next.js will always set NODE_ENV to production, so there is no preview, staging or testing state

Another option is if, like me, you deploy on Vercel, then you can use the VERCEL_ENV variable, which is development when running your project locally or preview when deploying a preview on Vercel and production when deploying a production build on Vercel

The third option to know the current context is to use the Next.js config property called phase, to get the phase phase property, we need to convert nextConfig into a function

In this tutorial we are going to use the 3rd option, the example I will present will use the phase to check if the current phase is development or production and then only enable typed routes for development, we use this workaround because of a bug in typed routes, to learn more about the bug, check out to the previous part "Typescript plugin and typed routes"

Using Next.js configuration phase

In the previous part of the tutorial we chnaged our configuration code in next.config.mjs to this:

next.config.mjs
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants.js'
 
const nextConfig = (phase) => {
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        experimental: {
            // experimental typescript "statically typed links"
            // https://nextjs.org/docs/app/api-reference/next-config-js/typedRoutes
            // currently false in prod until PR #67824 lands in a stable release
            // https://github.com/vercel/next.js/pull/67824
            typedRoutes: phase === PHASE_DEVELOPMENT_SERVER ? true : false,
        },
    }
 
    return nextConfigOptions
 
}
 
export default nextConfig

Line 1: we import the PHASE_DEVELOPMENT_SERVER constant from the next/constants

Line 3: we have converted our next config object into a function, which means we now have access to the phase parameter, it will allow us to check what the current context of our Next.js app is

Line 12: we check if the phase is development server by checking if the content of our phase variable is equal to PHASE_DEVELOPMENT_SERVER, if it is, we enable typedRoutes, and if it is NOT, we disable the typedRoutes option

React strict mode configuration

React strict mode and powered by header(s) are two configuration options that often lead to controversial discussions among developers

React strict mode is enabled by default since Next.js v13.4 for the app router (not the pages router), you can disable the React strict mode in the next.config.mjs file by setting the option to false

Note

For example, if you do NOT want the Strict Mode to be enabled in your entire project, then disable it via the Next.js configuration file and then use the <StrictMode> only in the pages/layouts... in which you want to enable it

I recommend to NOT disable React Strict Mode, I see posts on Stack Overflow where people argue to turn it off as it causes problems in their app, however, in my opinion, this is masking problems instead of fixing the root cause, as mentioned on react.dev the Strict Mode does several important things, one of them is checking if your components use deprecated APIs

Tip

Strict Mode will only run in development and NOT in production, this is another reason to keep it turned on, even if it would lead to a problem in development, it will NOT have any impact on your production build and hence have no impact on what your users experience

What surprises developers the most when they use React Strict Mode for the first time is that it re-renders components an extra time (in development)

What happens is that every component gets rendered (and effects triggered), then the components get unmounted and then get mounted a second time, which triggers the rendering process and all of the effects a second time

This is done to detect problems. Here is the explanation from the React.dev documentation as to why this is done:

React components you write must always return the same JSX given the same inputs (props, state, and context). Components breaking this rule behave unpredictably and cause bugs.

If, for some reason, you don't want it to be enabled in your entire app or if you need to disable it temporarily, then you can do it in the Next.js configuration file

We will, however, leave the strict mode enabled as this is recommended:

next.config.mjs
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants.js'
 
const nextConfig = (phase) => {
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        reactStrictMode: true,
        experimental: {
            // experimental typescript "statically typed links"
            // https://nextjs.org/docs/app/api-reference/next-config-js/typedRoutes
            // currently false in prod until PR #67824 lands in a stable release
            // https://github.com/vercel/next.js/pull/67824
            typedRoutes: phase === PHASE_DEVELOPMENT_SERVER ? true : false,
        },
    }
 
    return nextConfigOptions
 
}
 
export default nextConfig

Next.js powered by header configuration

Next.js powered by header is another Next.js configuration option, if enabled, will add an x-powered-by header to all of your pages

To see the x-powered-by header for yourself, first open the browser dev tools (by pressing the F12 key or right-clicking somewhere in the page and choosing Inspect), then open the Network Tab and then click on the row for the page, then click on Headers and look at the entries for the response headers where you should have an entry for x-powered-by, like in this screenshot:

chrome dev tools network tab showing the powered by header

Why would you want to hide the x-powered-by header?

When I get asked this, my first thought is to ask myself the opposite: "Why would I want to turn it on?"

Honesty,y I have not yet found a reason as to why I would want to have it turned on

I prefer to turn it off because, unfortunately, some people on the web have malicious intentions, and the less they know about your app’s technology stack, the more difficult it will be for them to find vulnerabilities that have been disclosed but are not yet patched in the version you are using

I agree that it does NOT make a huge difference if you turn it on or off because hackers usually just launch batteries of tests against your website, which will probe it for a wide range of known vulnerabilities

Few will use a bot that checks for x-powered-by headers to target the framework you are using specifically, and it is also true that hackers can use profiling tools to get approximative information about what tech stack you are using.

So I agree that setting the poweredByHeader option in the Next.js configuration to off is not a miracle solution that will prevent all potential attacks, but if there is a chance (no matter how small) that turning it off will make my app just a little bit safer, then that's good enough for me and as I said earlier the second reason is that I see no reason why I would want to turn it on

So, if you also want to turn the poweredByHeader option off, open the Next.js configuration file and change it to this:

next.config.mjs
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants.js'
 
const nextConfig = (phase) => {
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        reactStrictMode: true,
        poweredByHeader: false,
        experimental: {
            // experimental typescript "statically typed links"
            // https://nextjs.org/docs/app/api-reference/next-config-js/typedRoutes
            // currently false in prod until PR #67824 lands in a stable release
            // https://github.com/vercel/next.js/pull/67824
            typedRoutes: phase === PHASE_DEVELOPMENT_SERVER ? true : false,
        },
    }
 
    return nextConfigOptions
 
}
 
export default nextConfig

If you did any of the two changes I mentioned above, then save your next.config.mjs and commit/sync your latest changes to your git repository with a commit message like, for example: "turning off powered by the header as I see no reason to have it enabled"

Redirects

If the project you are building is going to replace an existing project, then you might want to add some redirects. When using Next.js, adding redirects is really easy, so I won't do a deep dive, but I just wanted to mention that this can be done in the next.config.mjs:

static redirect example
const nextConfig = (phase) => {
 
    const withMDX = createMdx({
        options: {
            remarkPlugins: [],
            rehypePlugins: [],
        },
    })
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        redirects: async () => {
            return [
                {
                    source: '/my-old-url',
                    destination: '/my-new-url',
                    permanent: true,
                },
            ]
        },
    }
 
    return withMDX(nextConfigOptions)
 
}

It is usually best to change URLs as few as possible because search engines have indexed those pages and some users might have bookmarked them. But especially when switching from the pages router to the app router, you might want to do some redirects for pages you have migrated to a new URL. For those cases, Next.js has a very powerful feature that allows you to redirect old dynamic routes to new dynamic routes:

static redirect example
const nextConfig = (phase) => {
 
    const withMDX = createMdx({
        options: {
            remarkPlugins: [],
            rehypePlugins: [],
        },
    })
 
    /** @type {import('next').NextConfig} */
    const nextConfigOptions = {
        redirects: async () => {
            return [
                {
                    source: '/my-old-url-with-a/:slug',
                    destination: '/my-new-url-with-a/:slug',
                    permanent: true,
                },
            ]
        },
    }
 
    return withMDX(nextConfigOptions)
 
}

A lot more is possible, if you want to know more about wildcards, regex support, and even redirects based on data in headers or cookies, then I recommend checking out the official redirects documentation, which has lots of examples

Congratulations 🎉 you now know how to use phases and make adjustments to the Next.js configuration

If you liked this post, please consider making a donation ❤️ as it will help me create more content and keep it free for everyone