Ensure Code Separation in Next.js: Server Only vs Client Components

Ensure Code Separation in Next.js: Server Only vs Client Components

Β·

3 min read

Next.js is a popular framework for building server-rendered React applications. However, when JavaScript modules are shared between server and client components, it can introduce a potential vulnerability. This blog post will explore the risks associated with server-only code leaking into client components and present a solution using the "server-only" package in Next.js. We will learn how to identify and restrict server-specific code from being imported into client components, ensuring code integrity and security.

Understanding the Risk

When developing web applications, it is essential to differentiate between code that should only run on the server and code suitable for client-side execution. Failure to do so can result in the leakage of sensitive information or the execution of code in an unintended context. Let's examine an example to understand this risk:

// lib/data.ts

export async function getData() {
  const res = await fetch('https://external-service.com/data', {
    headers: {
      authorization: process.env.API_KEY,
    },
  });

  return res.json();
}

In the above code snippet, getData() appears to work on both the server and the client. However, the authorization header relies on the process.env.API_KEY, which is a private environment variable accessible only on the server. Next.js automatically replaces private environment variables with an empty string in client code to prevent the leakage of secure information. Consequently, although getData() can be imported and executed on the client, it won't function as intended. Making the variable public would resolve the issue but would compromise sensitive information.

Meet the "server-only" Package

To prevent the accidental usage of server-only code in client components, Next.js provides the "server-only" package. This package helps developers identify and restrict the usage of server-specific code, ensuring its execution exclusively on the server.

Installation

Install the "server-only" package using the following command:

npm install server-only

Implementation

Now importing the "server-only" package, any client component that attempts to import the server-only module will encounter a build-time error, clearly indicating that the module can only be used on the server.

Example:

// lib/data.ts

import 'server-only';

export async function getData() {
  // Code that should only run on the server
}

Bonus πŸ”₯

Handling Client-Only Code

Next.js also offers the "client-only" package to handle modules containing client-only code, such as those relying on browser-specific APIs like the window object. Marking modules with "client-only" ensures they are only used on the client-side, preventing unintended access or execution on the server.

Installation

Install the "client-only" package using the following command:

npm install client-only

Implementation

By importing the "client-only" package, any server component that mistakenly imports the client-only module will generate a build-time error, notifying developers that the module can only be used on the client.

// lib/client-only-module.ts

import 'client-only';

// Client-only code utilizing browser-specific APIs

Like what you see? πŸ’˜

Feel free to follow me on Twitter, GitHub, and LinkedIn for more articles and insights on Next.js and other frontend development topics. Let's connect and stay updated on the latest trends and techniques in the world of web development!

- Twitter
- Github
- Linkedin

Β