‘use client’ in Next.js: What It Does, What It Costs, and When to Use It

28th Mar, 2026

The costs of interactivity from 'use client'

Specifying the use client directive for a Nextjs component makes it a Client Component. But that doesn’t mean the component only renders on the client-side. It is still rendered on the server.

So what does the directive use client actually do?

The use client directive tells Nextjs that this component must also run in browser - enabling things like React hooks (useState, useEffect) and event handlers (onClick).

Below is a quick summary of what use client changes:

Directive
Renders on
Server?
JS shipped
to browser?
Hydrates
on client?
Can use
hooks?
Server Component (default)
Yes
No
No
No
Client Component (use client)
Yes
Yes
Yes
Yes

But what does it mean for a component to ship JavaScript to the browser or to hydrate on the client? And what do you pay for enabling this interactivity? Let’s delve into the details.

This post focuses on pages where loading performance and SEO matter (like eComm, marketing, content pages).

For highly interactive apps (like dashboards), using use client more broadly is often appropriate, but is beyond the scope of this post.

1. Example code repositories for this post

To understand the impact of the use client directive, we’ll compare two nearly identical Next.js applications.

Both applications:

  • Fetch and render the same list of products
  • Have the same UI The difference between the two is that one is purely server-rendered with no browser-side interactivity. The other enables browser-side interactivity using use client components.

1.1. Server Component version

This version uses the default Server Component throughout and does not include any browser-side interactivity.

1.2. Client Component version (with ‘use client’)

This version renders the same UI, but enables interactivity by using use client in the top-level component and several child components.

The rest of the post uses to these two implementations to observe the differences.

2. What ‘use client’ actually does

Adding a use client directive to a component doesn’t switch off server-side rendering for the component. As you can see below, both versions still return fully rendered HTML from the server.

view-source:https://no-use-client.vercel.app/
View source for a server component
view-source:https://with-use-client.vercel.app/
View source for a client component

Both versions return fully rendered HTML from the server, even when use client is used.

The presence of use client tells Next.js to:

  • send the JavaScript for that component and other components that also use use client to the browser.
  • when the page loads in the browser, React hydrates these components so they become interactive.

Learn more about React hydration here

2.1 How ‘use client’ enables browser-side interactivity

We need use client to specify to Nextjs that the component requires browser-side interactivity. A couple of trivial examples:

  • A hamburger menu that expands when clicked (uses onClick).
  • An email input field changes the border to red if the entered email address is in an invalid format (uses onChange + useState).

To implement such interactivity, we rely on React hooks (like useState) and event handlers (like onClick). These only work in Client Components.

Even simple interactions like handling a button click require use client, even if no hooks are used.

'use client';

import { useState } from 'react';

export default function EmailInput() {

  // useState enables interactivity, 
  // which requires `use client`
  const [email, setEmail] = useState('');
  const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  return (
    // onChange work only in Client Components
    <input
      type="email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
      style={{ borderColor: email && !isValid ? 'red' : '' }}
    />
  );
}

Using hooks without use client will cause Nextjs to throw an error:

> Build error occurred
Error: Turbopack build failed with 1 errors:
./components/AddToCartButton.tsx:1:10
You're importing a module that depends on `useState` into a React Server Component module.
This API is only available in Client Components. 
To fix, mark the file (or its parent) with the `"use client"` directive.
Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client

> 1 | import { useState } from 'react'
    |          ^^^^^^^^
  2 |
  3 | export default function AddToCartButton({ productId }: { productId: number }) {
  4 |   const [added, setAdded] = useState(false)
Server Components render HTML only.
Client Components render HTML and run JavaScript in the browser.

3. The costs of ‘use client’ directive

When we specify use client for a component, it has the following implications:

3.1. Bundle size

Server Components do not send their JavaScript to the browser, while Client Components do (to enable interactivity). As a result, Client Components increase the amount of JavaScript shipped to the browser.

For our example demo app, following is the size of JavaScript loading in the browser:

Url
JavaScript Bundle Size (gzipped)
https://no-use-client.vercel.app
157 kB
https://with-use-client.vercel.app
215 kB

This is not a like-for-like comparison, since https://no-use-client.vercel.app has no interactivity while https://with-use-client.vercel.app allows filtering and sorting of products. The comparison is meant to highlight the JavaScript cost of interactivity.

Even without any use client components, the JavaScript shipped isn't 0 kB. A baseline bundle is still needed for React runtime and Next.js client-side routing.

3.2. Hydration cost

When a Client Component’s JavaScript reaches the browser, React needs to hydrate it to make the component interactive.

Hydration runs on the browser’s main thread and competes with other work (like handling user input and rendering). The more client-side JavaScript you have, the more work React has to do during hydration.

This can delay interactivity and contribute to sluggish responsiveness (for example, affecting metrics like INP).

3.3. Data fetching waterfall

When a component with a use client directive needs to fetch data, it cannot fetch data like this:

'use client'

export default function HomePage() {
  // Fetching like this isn't allowed in Client Components
  // since they cannot be async functions
  const products = await fetchProducts()

  return (
    <>
    /* JSX to render products */
    </>
  );
}

Instead, data fetching inside Client Components requires using hooks like useEffect:

'use client'
import { useState, useEffect } from 'react';

export default function HomePage() {
  // Fetching on-load for client components requires
  // using hooks like the following.
  const [products, setProducts] = useState([]);
  useEffect(() => {
    fetchProducts()
    .then((data) => {
      setProducts(data)
    })
  }, []);

  return (
    <>
    /* JSX to render products */
    </>
  );
}

With this pattern, when a page loads:

  • The HTML is rendered first (without the data)
  • JavaScript is downloaded and hydrated
  • Only then data fetching begins in the browser
Data fetching within Client Components
Fetching happens after hydration (client-side).
Data fetching with Server Components
Fetching happens during server render.

Data fetching in Client Components typically happens after hydration. This:

  • delays display of the content during page loading
  • results in the initial HTML not containing the page content

Also, streaming in React happens only when a Server Component suspends during render. Moving data fetching to useEffect removes these suspension points and eliminates progressive streaming. The result is an initial HTML shell that is populated only after hydration.

The costs of Client Components compound:

More JavaScript → more hydration work → enabling client-side data fetching patterns after hydration.

As a result of the above costs, use client should always be used deliberately and not by default.

4. SEO Impact

Using the use client directive by itself does not inherently harm SEO, since the initial HTML still contains the page content.

But, if a Client Component fetches data on the client (for example, inside useEffect), the initial HTML may not include that content. In such cases, search engines need to rely on JavaScript execution to see the content. This is slower and less reliable and can have a negative SEO impact.

5. The right pattern for ‘use client’

For performance and SEO sensitive pages, use client should be used within components needing interactivity. And, ideally these should be leaf components. This keeps most of the component tree as Server Components, reducing JavaScript sent to the browser and minimizing hydration work. Using it at the top-level should generally be avoided.

Using use client within leaf components
Using use client within leaf components

Also, a server component can be passed as children or as a prop to a client component and React does not convert it into a Client Component. See the code example below:

//////// page.tsx
import ProductCard from '@/components/ProductCard'
import FilterBar from '@/components/FilterBar'

export default async function HomePage() {
  const products = await fetchProducts()

  /* Homepage is a server component that passes another
  Server Component ProductCard to FilterBar as a prop */
  return (
    <FilterBar products={products} CardComponent={ProductCard} />
  );
}



//////// FilterBar.tsx
// Is a client component to enable filtering 
// of products via useState
'use client'
import { useState } from 'react'

export default function FilterBar({ products, CardComponent }: Props) {
  const [category, setCategory] = useState('all')
  const filtered = products
    .filter((p) => category === 'all' || p.category === category)
  return (
    <>{filtered.map((product) => (
      <CardComponent key={product.id} product={product} />
    ))
    }</>
  )
}



//////// ProductCard.tsx
// Is not a client component even though rendered through
// FilterBar because it is passed from a Server Component
export default function ProductCard({ product }: { product: Product }) {
  return (
    /* Code to display product card */
  )
}

Also, note that Client Components cannot import Server Components directly.

6. When to use and avoid ‘use client’

Based on the trade-offs discussed above, the following guideline can help decide when to use the use client directive:

Use use client when:
Component requires React hooks (like useState, useEffect, useRef, useContext)
Component attaches event handlers (like onClick, onChange, onSubmit)
Component uses browser APIs (like window, navigator, localStorage)
Avoid use client when:
Component fetches data that can be fetched on the server (prefer Server Components and pass data as props).
Component only renders data without requiring interactivity.

Prefer Server Components by default, and use use client only where needed because the cost of interactivity shows up in larger bundles, hydration work and slower content loading.

Punit's Photo

Want a fast frontend that scales?

I've built and improved B2C frontends serving 2M+ monthly users to:

  • Optimize Core Web Vitals
  • Solve scalability issues
  • Implement SEO compliance
  • Select the right framework, library and hosting platform
  • Incrementally migrate or upgrade frontend frameworks

B2C clients Include:

purplle.com Logo mpl.live Logo wedmegood.com Logo
Discuss your frontend needs →

Or email: punit@tezify.com


Improve frontends More posts on Optimizing Frontends
Copyright (c) 2017-2026 Tezify All Rights Reserved. Created in India. GSTIN : 24BBQPS3732P1ZW.
Privacy Policy Terms of Service