Proper Usage Patterns for the use client Directive in Next.js App Router

Understand how the use client directive propagates in Next.js App Router and learn the best patterns for placing it at the server-client component boundary.

Basics of Next.js App Router

In Next.js App Router, Server Components are adopted by default. This means components are rendered on the server side, and only HTML and minimal JavaScript are sent to the client. This provides benefits such as faster initial loads and improved SEO.

On the other hand, components that require client-side interactive features (event handling, Hooks, etc.) need to be marked as Client Components. To use a client component, you declare the "use client" directive at the top of the file.

Proper Usage of use client

The "use client" directive can be declared anywhere, but it is recommended to limit its use to the boundary between Client Components and Server Components.

Propagation of use client

A file where "use client" is declared not only becomes a client component itself, but all components imported from it are also automatically treated as client components. In other words, "use client" propagates from the declared file to the entire downstream component tree.

For example, if a ParentComponent with "use client" declared imports a ChildComponent, the ChildComponent will be rendered as a client component even if its file does not contain "use client".

Maintaining Flexibility and Performance

If you don’t understand this propagation behavior and declare "use client" in unnecessarily many files, the following problems can occur:

  • Unnecessary client-side processing: Components that could have been rendered on the server are treated as client components, increasing bundle size and client-side rendering time.
  • Reduced component flexibility: When developing versatile UI components, the flexibility to use them as either server or client components is lost.

Conclusion: Declare at the Boundary

Therefore, it is important to declare "use client" only at the topmost component where the switch from server to client components is needed. This maintains component flexibility, avoids unnecessary client-side processing, and maximizes the benefits of App Router.

// app/page.tsx (Server Component)
import ClientComponent from './ClientComponent';

export default function HomePage() {
  return (
    <div>
      <h1>Welcome!</h1>
      <ClientComponent /> {/* Import the client component here */}
    </div>
  );
}

// app/ClientComponent.tsx (Client Component)
"use client"; // Declare the boundary here

import React, { useState } from 'react';

export default function ClientComponent() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times.
    </button>
  );
}

References