How to Fix “Functions Cannot Be Passed Directly to Client Components” error in Next.js

In Next.js, especially when using the new app directory structure, you might encounter the following error when attempting to pass a function from a Server Component to a Client Component:

Thank me by sharing on Twitter 🙏

Plaintext
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
Or maybe you meant to call this function rather than return it.
<... customers={[...]} mergeCustomers={function mergeCustomers}>

This error happens because Next.js enforces a strict separation between server-side and client-side code. Server-side functions can’t be passed directly to Client Components, as they belong to different environments. To resolve this, you need to explicitly mark the server-side function with use server and handle the function passing properly.

Why Does This Error Happen?

In Next.js, functions that involve server-side operations (like fetching data or interacting with databases) should not be passed directly to Client Components. Client Components are rendered in the browser, which doesn’t have access to the server-side logic. The solution is to mark these server-side functions with use server and ensure they are only called from the server.

Solution: Use use server and Pass the Function from the Page Component

Let’s walk through how to fix this error by marking the function as a server-side function and passing it down to the Client Component properly, where it will be called upon a button click.

1. Create a Server-Side Function

Start by creating the server-side function in its own file. This function will handle any logic that should only be run on the server (e.g., interacting with a database or fetching external data). Make sure to add use server at the top of the file to declare that it should run server-side.

Here’s an example:

TypeScript
// src/lib/mergeCustomers.js

"use server";

export async function mergeCustomers(customers) {
  // Your server-side logic for merging customers
  return customers.map(customer => ({
    ...customer,
    merged: true,  // Example modification
  }));
}

By marking it with use server, you’re telling Next.js that this function should only run on the server.

2. Pass the Function to the Page Component

In your page file, you can import this server-side function and pass it down to the Client Component. Instead of executing the function on the server, you’ll pass it to the Client Component where it will be called upon a button click.

TypeScript
// src/app/page.js

import { mergeCustomers } from '../lib/mergeCustomers';
import ClientComponent from './ClientComponent';

export default async function Page() {
  const customers = await getCustomers();  // Fetch data or initialize customers array

  return (
    <ClientComponent customers={customers} mergeCustomers={mergeCustomers} />
  );
}

In this example, the mergeCustomers function is passed down as a prop to the ClientComponent. The Client Component will handle calling the function.

3. Call the Function from the Client Component on a Button Click

Now, update your ClientComponent to take the mergeCustomers function as a prop and call it on a button click. This allows the client to trigger the server-side function when needed.

TypeScript
// src/app/ClientComponent.js

import { useState } from 'react';

export default function ClientComponent({ customers, mergeCustomers }) {
  const [mergedCustomers, setMergedCustomers] = useState(customers);

  const handleMerge = async () => {
    const result = await mergeCustomers(mergedCustomers);
    setMergedCustomers(result);  // Update the state with the merged customers
  };

  return (
    <div>
      <h1>Customer List</h1>
      <ul>
        {mergedCustomers.map(customer => (
          <li key={customer.id}>{customer.name} - {customer.merged ? "Merged" : "Not Merged"}</li>
        ))}
      </ul>
      <button onClick={handleMerge}>Merge Customers</button>
    </div>
  );
}

In this updated version of ClientComponent, when the “Merge Customers” button is clicked, the mergeCustomers function is called, and the resulting data is used to update the component’s state and re-render the UI.

Verifying the Fix

To verify that the solution works, run the application. The Client Component should render the customer list as expected. When you click the “Merge Customers” button, the customer list should update to show the merged status, and the error about passing functions directly to Client Components should no longer appear.

Conclusion

By marking the server-side function with use server and passing it down to the Client Component where it is triggered through user interaction, you can resolve the error. This approach ensures that server-side logic is kept separate from client-side code while still allowing interaction between the two when necessary.

This method is a best practice in Next.js, especially in the app directory, where the separation of client and server code is critical for performance and maintainability.

Tags/Keywords: Next.js, Client Components, Server Components, JavaScript, Error Handling, React.

Share this:

Leave a Reply