Converting Server Components to Client Components in Next.js: A Beginner’s Guide



This content originally appeared on DEV Community and was authored by sudip khatiwada

When working with Next.js 13+ and the App Router, understanding the difference between Server Components and Client Components is crucial for building efficient web applications. Sometimes, you’ll need to convert a Server Component into a Client Component. Let’s explore when, why, and how to do this properly.

What Are Server Components vs Client Components?

Server Components (Default)

  • Run on the server during build time or request time
  • Cannot use browser-specific features like useState, useEffect, or event handlers
  • Great for fetching data and rendering static content
  • Smaller JavaScript bundle size

Client Components

  • Run in the browser after the page loads
  • Can use React hooks and browser APIs
  • Handle user interactions like clicks, form inputs
  • Require the "use client" directive at the top

When Do You Need Client Components?

You need to convert to Client Components when you want to:

✅ Use React hooks (useState, useEffect, etc.)

✅ Handle user interactions (onClick, onSubmit)

✅ Access browser APIs (localStorage, window object)

✅ Use event listeners

✅ Create interactive UI elements

Simple Code Example: Converting Server to Client Component

Let’s see a practical example of converting a Server Component to a Client Component.

Before: Server Component (Won’t Work for Interactions)

// app/components/Counter.jsx
// This is a Server Component by default

export default function Counter() {
  // ❌ This won't work in Server Components
  // const [count, setCount] = useState(0);

  return (
    <div>
      <h2>Counter: 0</h2>
      {/* ❌ onClick won't work in Server Components */}
      <button>Click me</button>
    </div>
  );
}

After: Client Component (Interactive Version)

// app/components/Counter.jsx
"use client"; // ✅ This makes it a Client Component

import { useState } from 'react';

export default function Counter() {
  // ✅ Now we can use useState
  const [count, setCount] = useState(0);

  // ✅ Event handlers work in Client Components
  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h2>Counter: {count}</h2>
      {/* ✅ onClick works perfectly now */}
      <button onClick={handleClick}>
        Click me to increase!
      </button>
    </div>
  );
}

Using the Component in Your Page

// app/page.jsx
import Counter from './components/Counter';

export default function HomePage() {
  return (
    <div>
      <h1>My Next.js App</h1>
      <Counter />
    </div>
  );
}

Step-by-Step Conversion Process

Step 1: Add “use client” Directive

Add "use client"; at the very top of your component file.

Step 2: Import Required Hooks

Import any React hooks you need from ‘react’.

Step 3: Add Interactive Logic

Now you can add state, event handlers, and other interactive features.

Real-World Example: Contact Form

Here’s a more practical example showing a contact form conversion:

Server Component (Static Form)

// app/components/ContactForm.jsx
export default function ContactForm() {
  return (
    <form>
      <input type="text" placeholder="Your Name" />
      <input type="email" placeholder="Your Email" />
      <textarea placeholder="Your Message"></textarea>
      <button type="submit">Send Message</button>
    </form>
  );
}

Client Component (Interactive Form)

// app/components/ContactForm.jsx
"use client";

import { useState } from 'react';

export default function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form submitted:', formData);
    // Handle form submission logic here
  };

  const handleChange = (e) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text" 
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="Your Name" 
      />
      <input 
        type="email" 
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Your Email" 
      />
      <textarea 
        name="message"
        value={formData.message}
        onChange={handleChange}
        placeholder="Your Message"
      ></textarea>
      <button type="submit">Send Message</button>
    </form>
  );
}

Best Practices and Tips

✅ Do This:

  • Keep Server Components as the default when possible
  • Only convert to Client Components when you need interactivity
  • Use Client Components for forms, buttons, and dynamic UI
  • Place “use client” at the top of the file

❌ Avoid This:

  • Don’t make everything a Client Component
  • Don’t forget the “use client” directive when needed
  • Don’t try to use hooks in Server Components

Performance Considerations

Server Components Benefits:

  • Faster initial page load
  • Better SEO
  • Smaller JavaScript bundle
  • Server-side data fetching

Client Components Trade-offs:

  • Larger bundle size
  • Runs in browser (uses client resources)
  • Better for interactivity and user experience

Common Errors and Solutions

Error: “You’re importing a component that needs useState”

Solution: Add "use client" directive to the component.

Error: “Event handlers cannot be passed to Server Components”

Solution: Convert the component to a Client Component with "use client".

Conclusion

Converting Server Components to Client Components in Next.js is straightforward once you understand the key differences. Remember:

  1. Server Components are great for static content and data fetching
  2. Client Components are essential for interactivity and user interactions
  3. Add "use client" at the top when you need browser features
  4. Use the right component type for the right job

By following these guidelines and examples, you’ll be able to build efficient, interactive Next.js applications that provide the best user experience while maintaining optimal performance.

Ready to build your next interactive Next.js application? Start with Server Components by default and convert to Client Components only when you need that extra interactivity!


This content originally appeared on DEV Community and was authored by sudip khatiwada