9 November 2023
Implementing maintenance mode in Next.js apps

Blazity

When managing a Next.js project, it's essential to have a strategy in place for times when the site needs to go into maintenance mode. Here are some options for effectively implementing such a mode.
Wojtek Wrotek
Wojtek Wrotek
React/Next.js Frontend Developer
Implementing maintenance mode in Next.js apps

Introduction

When managing a Next.js project, it's essential to have a strategy in place for times when the site needs to go into maintenance mode. This ensures that users are not faced with a broken or insecure site during updates or fixes. This article discusses how to implement such a mode effectively, with an emphasis on minimizing disruption and maintaining a professional user experience during these pauses in service.

Solution 1: next-maintenance-mode library

Next-maintance-mode is a middleware specially designed for Next.js applications, enabling to toggle maintenance mode on and off easily. When activated, it redirects users to a designated maintenance page, while still keeping essential parts of the site operational. Its compatibility with configuration providers such as Upstash and Edge Config allows for flexible and dynamic maintenance state management.

Provider

Reads (free plan)

Vercel/Edge-Config

50k/month

Upstash/Redis

~ 300k/month (10k/day)

Our solution also includes an optional caching feature to help save bandwidth. It uses LRU cache under the hood. While it may not be the best solution it still helps to reduce bandwidth usage. Due to edge functions nature, the LRU cache might occasionally reset, but it's nothing to worry about. If this happens, the status is automatically checked in the provider and updated. This won't affect passed middleware's functions - they are not cached.

Code

1import { withMaintenanceMode } from 'next-maintenance-mode'
2
3const middlewareOptions = {
4  provider: 'upstash' | 'edge-config', // Required
5  maintenancePageSlug: '/maintenance', // Optional
6  key: 'your_key_here', // Optional
7  cacheTime: 'number', //Optional - defined in ms for e.g. 60000 = one minute
8}
9
10withMaintenanceMode(
11  {
12    beforeCheck: NextMiddleware, // function which will be executed before checking the maintenance mode (if an instance of NextResponse is returned, checking maintenance mode status & afterCheck is skipped) 
13    afterCheck: NextMiddleware, // function which will be executed after checking the maintenance mode (only if maintenance mode status is set to false)
14  },
15  'your_connection_string_here',
16  middlewareOptions,
17)

You can also easily access the req parameter in passed middleware functions, this allows for seamless integration with for e.g. next-auth.

Code

1import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
2import { withMaintenanceMode } from "next-maintenance-mode";
3import { getToken } from "next-auth/jwt";
4
5async function firstMiddleware(req: NextRequest, _next: NextFetchEvent) {
6
7  const token = await getToken({ req });
8  if (!token) {
9    return NextResponse.rewrite(new URL("/sign-in", req.nextUrl));
10  }
11  if (token.role === "admin") {
12    return NextResponse.next(); //If you want you can disable checking maintenance mode for users with an admin role
13  }
14}
15
16async function secondMiddleware(req: NextRequest, _next: NextFetchEvent) {
17  console.log("secondMiddleware");
18}
19
20export default withMaintenanceMode(
21  { beforeCheck: firstMiddleware, afterCheck: secondMiddleware },
22  process.env.MAINTENANCE_MODE_CONNECTON_STRING as any,
23  {
24    provider: process.env.MAINTENANCE_MODE_PROVIDER as any,
25    maintenancePageSlug: process.env.MAINTENANCE_MODE_PAGE_SLUG,
26    key: process.env.MAINTENANCE_MODE_KEY,
27  }
28);
29
30
31export const config = {
32  matcher: ["/((?!api/auth|_next/static|_next/image|favicon.ico).*)"],
33};
34

By splitting functions to execute either before or after checking maintenance status you can for e.g. allow users with admin rights to access the page while every other user will be presented with the maintenance mode page.


Apart from that you can also use updateMaintenanceModeStatus function which allows you to toggle the maintenance mode from the server side for e.g. route handler. It means that you can easily create an admin panel where itā€™d be possible to toggle the mode. Or if any critical error occurs for e.g. if a test fails you can toggle it automatically.

Try it out yourself!

šŸ› ļø Next.js Maintenance Mode

Solution 2: Using middleware

Vercel has created a template that uses edge config (global datastore). Itā€™s an easy-to-implement and simple solution. It uses Next.js middleware, evaluating each request to see if the maintenance mode is activated. Simple, right? However, thereā€™s a catch. If you exceed 50,000 reads per month, it can become expensive. For websites that have a significant volume of traffic, the number of reads can quickly add up, leading to unexpected costs.

Maintenance page example

Solution 3: Conditional rendering

Using conditional rendering for a maintenance mode in Next.js involves displaying a <MaintenancePage/> component instead of the usual application content when an environment variable indicates maintenance is active. This can be quickly implemented by checking the environment variable in the _app.js file and rendering the maintenance page accordingly.


Here's a more detailed look at how this could be structured within your _app.js file:

Code

1function MyApp({ Component, pageProps }) {
2  if (process.env.MAINTENANCE_MODE === 'true') {
3    // Render the maintenance page instead of the regular component
4    return <MaintenancePage />;
5  }
6
7  // Otherwise, render the normal component
8  return <Component {...pageProps} />;
9}

However, this method doesn't restrict access to API routes, which remain functional and might cause inconsistent behavior if accessed directly during maintenance. Additionally, if the build process relies on live data (used for e.g. in middleware file) that's unavailable during maintenance, it could lead to build failures.


To address these drawbacks, developers might need to implement additional checks or fallbacks for API routes and ensure that the build process can handle unavailable data, either through error handling or by using cached data. This can make the logic more complex and hard to maintain.

Solution 4: A separate branch

Using Vercel deployment, an effective strategy for displaying a maintenance page might be to create a separate branch named, for example, ā€œmaintenance-pageā€. This method avoids the need to change anything in the database, providing a seamless way to switch to a maintenance view when required. Within Vercel, you can use the ā€œpromote to productionā€ function, enabling the selected branch to replace the existing production deployment. This approach ensures that the construction and deployment of the project continue uninterrupted, even if thereā€™s a failure in the backend. However in this case there are several major issues:


  • Third-Party Dependency: Relies on Vercel's uptime, with no control during their outages.
  • Time Delays: Switching to maintenance mode is not instant due to build times.
  • Rollback Complexity: Returning to the main site requires another build, adding downtime.


Conclusion

To summarize, when dealing with backend issues or security vulnerabilities in Next.js projects, it's important to have an effective maintenance mode strategy. The options considered include using middleware for global datastore checks, conditional rendering, creating a separate branch for maintenance, and utilizing the next-maintenance-mode library. Each has its considerations, such as potential costs, exposure of API routes, build-time dependencies, and downtime for deployment.


The next-maintenance-mode library stands out by offering an easily integrated, cost-effective solution that ensures the frontend can display a maintenance page while selectively allowing access to certain users, like admins, without significant performance drawbacks or unexpected expenses.

šŸ› ļø Next.js Maintenance Mode

blazity comet
Get a quote
Empower your vision with us today
The contact information is only used to process your request. By clicking send, you agree to allow us to store information in order to process your request.