Detecting server vs client in NextJS application
Next.js, a popular React framework, helps you to build powerful web applications with ease. However, managing server-side and client-side execution can pose unique challenges. In this article, we’ll explore techniques for detecting server or client execution in Next.js applications.
Table of Content
- What is Server Side Rendering?
- What is Client Side Rendering?
- Detecting server vs client-side rendering
- 1: Using typeof window
- 2: Using process.browser
- 3: Using a custom flag
- 4: Using req object in getServerSideProps
- 5: Using window object inside useEffect
What is Server Side Rendering?
Server-side rendering (SSR) is a technique used to deliver HTML content to a client’s browser by pre-rendering it on the server. This approach helps reduce the load on the client’s browser and improves page loading times, resulting in faster access to web pages. A quick way to verify if an application is using SSR is to disable JavaScript in the client’s browser. If the requested page still loads with content, it indicates that server-side rendering is being employed.
What is Client Side Rendering?
Client-side rendering (CSR) is a method in which all webpage files, such as HTML, CSS, and JavaScript, are delivered to the client’s browser. The browser then processes these files locally to render the content on the webpage, requesting resources from the server as needed. This approach shifts the computational load to the client’s browser, potentially resulting in slower initial page loading times but allowing for more dynamic and interactive user experiences.
Detecting server vs client-side rendering
Detecting whether Next.js applications are running on the server side or the client side is indeed an essential task to avoid unnecessary hydration errors in our application. Hydration errors occur when there is a mismatch between the server-rendered content and the content rendered on the client side. Knowing whether the application is running on the client or server side is crucial for preventing such errors.
Steps to create a nextJS application
Step 1: Create a nextJS app
Run the following command and configure as shown in figure below to setup nextJS app.
npx create-next-app demo
Step 2: Start nextJS demo app
navigate to the created folder and run the application using following commands.
cd demo
If in case any error in creation check the dependencies and scripts below if any mismatch incase. use latest version if not update to latest one. use following command to update nextJS version.
npm install next@latest
Step 3: Access your application
For accessing your application visit http://localhost:3000
Approach 1: Using typeof window
Since window object is only available on the client side, you can use typeof window to check if it’s defined. If it’s undefined, the code is running on the server side.
Example:
//index.js
import Head from "next/head";
export default function Home() {
if (typeof window == "undefined") {
console.log("Application is on server side");
} else {
alert("Application is on client side");
}
return (
<>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h2>This is a demo page</h2>
</main>
</>
);
}
Output:
Approach 2: Using process.browser
Next.js provides a built-in variable process.browser which is true on the client side and false on the server side.
Example:
//index.js
import Head from "next/head";
export default function Home() {
if (process.browser) {
console.log("Variant 2: Application is on client side");
} else {
console.log("Variant 2: Application is on server side");
}
return (
<>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h2>This is a demo page</h2>
</main>
</>
);
}
Output:
Approach 3: Using a custom flag
You can set a custom flag during the server-side render and check for its presence on the client side.
Example:
//index.js
import Head from "next/head";
import { useEffect, useState } from "react";
export default function Home() {
const [isServer, setIsServer] = useState(true);
useEffect(() => {
setIsServer(false);
}, []);
if (isServer) {
console.log("Custom Flag: Application is on server side");
} else {
console.log("Custom Flag: Application is on client side");
}
return (
<>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h2>This is a demo page</h2>
</main>
</>
);
}
Output:
Approach 4: Using req object in getServerSideProps
In server-side rendering methods like getServerSideProps, you have access to the req object. If req is defined, it signifies that the code is executing on the server side. Since getServerSideProps exclusively operates on the server, any code within it will not be executed on the client side. Therefore, the else part meant for client-side execution will not be triggered.
Example:
//index.js
import Head from "next/head";
export default function Home({ isServer }) {
if (isServer) {
console.log("Application is on server side");
}
return (
<>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h2>This is a demo page</h2>
</main>
</>
);
}
export async function getServerSideProps(context) {
return {
props: {
isServer: !!context.req,
},
};
}
Output:
Approach 5: Using window object inside useEffect
If you’re using React hooks, you can utilize the useEffect hook and check for the window object. This method is particularly suitable for functional components. Since the useEffect hook is part of React, it executes on the client side after the component mounts. Therefore, if you simply need to determine if the code is running on the client side, this approach works well. For instance, it’s useful for generating a random number without encountering server-side errors.
Example:
//index.js
import Head from "next/head";
import { useEffect } from "react";
export default function Home() {
useEffect(() => {
if (typeof window == "undefined") {
console.log("Variant 1: Application is on server side");
} else {
alert("Variant 1: Application is on client side");
}
}, []);
return (
<>
<Head>
<title>Create Next App</title>
</Head>
<main>
<h2>This is a demo page</h2>
</main>
</>
);
}
Output:
Conclusion
In summary, detecting server vs client-side rendering in Next.js is essential for managing hydration errors and optimizing performance. Methods like checking typeof window, process.browser, custom flags, req object in getServerSideProps, and useEffect with the window object offer versatile approaches. By selecting the appropriate method based on specific requirements, developers can ensure seamless execution and enhance the user experience in Next.js applications.