When creating and managing a project, it is important to take into account the moments when the application will be unavailable due to maintenance. In the case of CMS systems, such as WordPress, there are various plug-ins that allow you to veil your site while you make changes or test new functionality.
But how to implement maintenance mode in Next.js? Is it as easy as configuring a plugin on WordPress for a few minutes?
Of course it is!
Challenge
While searching for a solution for maintenance mode in Next.js applications, I came across a lack of available tools that met my expectations in terms of speed, flexibility and ease of use.
Solution
To start, we create a route.ts file in the app -> api root folder, which will be responsible for handling the request for our maintenance mode:
import { serialize } from "cookie";
export async function POST(request: Request, params: { slug: string }) {
const data: { password: string } = await request.json();
const password = data.password;
const expirationTime = 4 * 60 * 60; // 4 hours
const cookie = serialize(process.env.PASSWORD_COOKIE_NAME!, "true", {
httpOnly: true,
path: "/",
maxAge: expirationTime,
});
if (process.env.PAGE_PASSWORD !== password) {
return new Response("incorrect password", {
status: 401,
});
}
return new Response("password correct", {
status: 200,
headers: {
"Set-Cookie": cookie,
},
});
}
The next step will be to create a component, the appearance of which, the user will see immediately after entering the site. Below is a sample design that can be customized:
"use client";
import React, { useState, useEffect } from "react";
const PasswordPromptDialog = () => {
const [password, setPassword] = useState("");
const [passwordIncorrect, setPasswordIncorrect] = useState(false);
const [noPassword, setNoPassword] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const request = await fetch(`/api`, {
body: JSON.stringify({ password }),
headers: { "Content-Type": "application/json" },
method: "post",
});
if (password) {
if (request.status !== 200) {
return setNoPassword(false), setPasswordIncorrect(true);
} else {
window.location.reload();
}
} else {
return setPasswordIncorrect(false), setNoPassword(true);
}
};
useEffect(() => {
setPassword("");
}, [passwordIncorrect]);
return (
<div>
<p>Maintenance mode is enabled!</p>
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">
Log In
</button>
</form>
{noPassword && (
<p
style={{
color: "red",
fontSize: "14px",
}}
>
Enter the password.
</p>
)}
{passwordIncorrect && (
<p
style={{
color: "red",
fontSize: "14px",
}}
>
The entered password is incorrect.
</p>
)}
</div>
</div>
);
};
export default PasswordPromptDialog;
The last step, will be to call the PasswordPromptDialogcomponent in the layout.tsx file as follows:
- in order to display this mode, we check the value of the environment variable MAINTENANCE_MODE,
- if the maintenance mode is to be enabled, we verify the contents of the cookies to determine user authentication and then display our maintenance mode content — otherwise, the default page content is displayed.
import { cookies } from "next/headers";
import PasswordPromptDialog from "@/components/PasswordPromptDialog/PasswordPromptDialog";
import "@/styles/globals.scss";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const isMaintenanceMode = process.env.MAINTENANCE_MODE === "true";
if (isMaintenanceMode) {
const cookieStore = cookies();
const loginCookies = cookieStore.get(
`${process.env.PASSWORD_COOKIE_NAME!}`
);
const isLoggedIn = !!loginCookies?.value;
if (!isLoggedIn) {
return (
<html lang="pl">
<body>
<PasswordPromptDialog />;
</body>
</html>
);
}
}
return (
<html lang="pl">
<body>{children}</body>
</html>
);
}
At the very end, just add the following environment variables to the project (.env) with fixed values:
MAINTENANCE_MODE=FALSE
PASSWORD_COOKIE_NAME=authorized
SEARCH_QUERY_NAME=password
PAGE_PASSWORD=YourPasswordForWebsite
Summary
Implementing maintenance mode in Next.js applications, contrary to appearances, is crucial when developing and managing a project. Although CMS systems, such as WordPress, offer a variety of plugins that allow you to obscure your site during maintenance work, implementing maintenance mode in Next.js may seem more challenging.
However, with the solution presented here, which relies on the use of cookies to store authentication information, creating maintenance mode becomes as simple an operation as configuring a plug-in in a CMS. Thanks to the use of cookies, we not only maintain flexibility and speed, but also increase the level of security by preventing JavaScript scripts from reading data (setting the httpOnly option).
In summary, the above solution allows quick and easy implementation of maintenance mode in Next.js applications, while giving the user full control over the appearance of the "veil" and authentication. In addition, the ability to quickly switch maintenance mode by changing the value of an environment variable makes our solution extremely flexible and adaptable to different design needs.
Other blog posts
Building Automating USPS Shipping Label Generation in Medusa
Explore how we created custom software solution for automated USPS shipping label generation in Medusa...
Building a Custom Order Mechanism for Trading Events in Medusa
In this article, we’ll show you how we created a custom order mechanism for trading events in Medusa...