14

I've just released my nextjs app to production using Vercel.

I'm loving the whole experience except for one tiny part: I would have loved to be able to put my app in maintenance mode, but this option does not seem available on Vercel.

My question is: Has anyone achieved this before and could share some details here?

I'm guessing it could be done at 2 levels:

  • Modifying my app so that if an environment variable (i.e MAINTENANCE_MODE=true) is detected, every page redirects to a maintenance screen. However, this is not ideal, because adding an environment variable on Vercel requires a deployment for it to be taken into account.
  • Having a simple per-project toggle to enable/disable maintenance mode from Vercel. That would be mind-blowing.
Marc Perrin-Pelletier
  • 12,696
  • 8
  • 28
  • 36

4 Answers4

27

"Maintenance Mode" can be achieved with an Environment Variable and redirects property in your next.config.js (requires Next.js 9.5.0 or newer).

module.exports = {
  redirects() {
    return [
      process.env.MAINTENANCE_MODE === "1"
        ? { source: "/((?!maintenance).*)", destination: "/maintenance.html", permanent: false }
        : null,
    ].filter(Boolean);
  }
};

This adds a wildcard route that matches incoming requests and then issues a temporary redirect the /maintenance.html location.

Note that you cannot make changes to a deployment (config or environment variables) without deploying again.


Old Answer

If you're not using Next.js or using an old version of Next.js, "Maintenance Mode" can be achieved with the redirects property in vercel.json.

{
  "redirects": [
    { "source": "/((?!maintenance).*)", "destination": "/maintenance.html", "permanent": false }
  ]
}
styfle
  • 22,361
  • 27
  • 86
  • 128
  • That's a great answer, thanks a lot! I'll try it asap. – Marc Perrin-Pelletier Jun 11 '20 at 05:11
  • 1
    Where must the maintenance.html file be? I tried putting it at the root of the project, in the `pages` folder and in the `public` folder. Redirection using the `vercel.json` file works great, but the file is not found! – Marc Perrin-Pelletier Jun 11 '20 at 06:54
  • You could create a file `/public/maintenance.html`. If instead, you want to use `/pages/maintenance.js`, then you would need to modify the "destination" to be `/maintenance ` since the file extension is stripped for pages. – styfle Jun 11 '20 at 18:53
  • 1
    The issue was not that the file was not found, rather that I had too many redirects, because "/maintenance.html" matches the "/(.*)" pattern, which leads to a redirect, so on. The solution for me was simply to add one direct by route in my app. – Marc Perrin-Pelletier Jun 11 '20 at 22:22
  • 1
    Ah yes, its stuck in an infinite redirect because every path will match. I updated the `source` property pattern to exclude anything that starts with `maintenance`. – styfle Jun 12 '20 at 13:56
  • 1
    Does not work if maintenance is a `/pages/maintenance` as `/_next/*` calls are also redirected and prevents loading any static (css/js). – atulmy Feb 23 '21 at 12:26
  • That's a great anser but if i understand correctly that requires a new "build" of the website which in some cases might take a lot of time ( imagine a continuous deploy situation where tests need to run and a Dockerfile has to be built ) so i think the ideal solution would not be implemented on next.config but instead on all routes using a wrapper? need some investigation. – kroe Mar 12 '21 at 18:18
  • 1
    I had the same [issue](https://stackoverflow.com/questions/62264995/how-do-i-put-a-nextjs-app-in-maintenance-mode-using-vercel#comment117270894_62310021) as @AtulYadav, which I solved by adding `_next` to the source pattern: `/((?!maintenance|_next).*)` – patrik csak Aug 05 '21 at 04:36
  • For some reason, this syntax doesn't work for me if I use it together with other properties. Even with `.filter(Boolean)` it complains about the null type. – Florian Walther Jul 01 '22 at 09:08
4

A different solution I am currently using would be to create a separate maintenance page and then conditionally intercept the rendering of the actual component based on an environment variable.

I achieve this by adjusting the _app.js code to:

function MyApp({ Component, pageProps }) {
  if (process.env.NEXT_PUBLIC_MAINTENANCE_MODE === 'false') {
    return <Component {...pageProps} />
  } else {
    return <Maintenance />
}

Note that as mentioned in earlier answers, this relies on the Vercel env variables, per their website: "A new Deployment is required for your changes to take effect."

Fesch
  • 313
  • 1
  • 4
  • 12
1

To add on to comment by @ptrkcsk, if you are going the route of putting a maintenance page in pages directory and are rendering images with the <Image> component from next/image you will also want to include your static folder to the redirects regex.

This is the source pattern that is working for me: /((?!maintenance)(?!_next)(?!static).*)

nightcoder
  • 43
  • 5
0
  1. Create a new file called _app.js inside the pages directory if it doesn't already exist.

  2. Add the following code to the file:

import React from 'react';

function MyApp({ Component, pageProps }) {
  const isMaintenance = true; // Set this to false when you're done with maintenance
  const MaintenancePage = () => <div>Maintenance mode</div>;
  
  return (
    <>
      {isMaintenance ? <MaintenancePage /> : <Component {...pageProps} />}
    </>
  );
}

export default MyApp;
  1. Customize the <MaintenancePage> component as per your requirements.

  2. When you want to enable maintenance mode, set isMaintenance variable to true. When you're done with maintenance, set it back to false.

  3. Optionally, you can also add some styling for the maintenance page by creating a CSS