Fix “Only Plain Objects” Warning in Next.js

If you’re building a web app with Next.js in 2025, you’ve probably come across this cryptic warning: “Warning: Only plain objects can be passed to Client Components from Server Components.” It sounds scary, right? Don’t worry—it’s a common issue, and it’s totally fixable! This guide will break down what this warning means, why it happens, and how to resolve it in a way that’s easy to understand, even if you’re new to Next.js.


What Does the “Only Plain Objects” Warning Mean?

The warning pops up in Next.js when you’re trying to pass data from a Server Component to a Client Component, but the data isn’t in the right format. Specifically, Next.js expects plain JavaScript objects (like { name: "John", age: 30 }), but you’ve passed something more complex—like a function, a class instance, or a Date object.

Why Does This Happen?

Next.js uses a powerful feature called the App Router (introduced in Next.js 13 and still rocking in 2025) to split your app into Server Components and Client Components. Here’s the deal:

  • Server Components run on the server, fetch data, and render HTML. They’re super fast because they don’t ship JavaScript to the browser.
  • Client Components run in the browser and handle interactive stuff, like button clicks or form inputs. They need to be “hydrated” with JavaScript.

When a Server Component passes data to a Client Component (via props), Next.js serializes the data into JSON. JSON only supports plain objects, arrays, strings, numbers, booleans, and null. If you try to pass something like a function or a complex object, Next.js throws the warning because it can’t serialize it properly.

A Quick Example

Imagine you have a Server Component that fetches user data and passes it to a Client Component:

// Server Component (page.js)
async function Page() {
  const user = {
    name: "John",
    createdAt: new Date(), // Uh-oh! Date object
    sayHello: () => "Hello!" // Uh-oh! Function
  };
  return <ClientComponent user={user} />;
}

// Client Component (ClientComponent.js)
'use client';
export default function ClientComponent({ user }) {
  return <div>{user.name}</div>;
}

Here, new Date() and sayHello aren’t plain objects. When Next.js tries to serialize user to pass it to the Client Component, it freaks out and shows the warning.


Why Should You Care About This Warning?

You might think, “It’s just a warning, not an error—can’t I ignore it?” Well, not really. Here’s why this matters:

  • Broken Features: Non-serializable data (like functions) might not work in the Client Component, causing bugs.
  • Performance Issues: Complex objects can slow down your app or cause hydration errors.
  • Bad User Experience: If the Client Component doesn’t render correctly, your users might see glitches.
  • SEO Impact: Errors in rendering can hurt your site’s search engine rankings, especially if Google can’t crawl your pages properly.

Fixing this warning makes your app faster, more reliable, and SEO-friendly—win-win!


Common Causes of the “Only Plain Objects” Warning

Let’s look at the most common reasons this warning shows up in Next.js apps:

  1. Passing Date Objects
    JavaScript Date objects aren’t JSON-serializable. For example, { createdAt: new Date() } will trigger the warning.
  2. Passing Functions or Methods
    Functions, like () => console.log("Hi"), can’t be serialized because JSON doesn’t support executable code.
  3. Passing Class Instances
    If you pass an instance of a class (like new User()), it’s not a plain object and will cause the warning.
  4. Passing Complex Data Structures
    Things like Map, Set, or custom objects with circular references can’t be serialized easily.
  5. Third-Party Library Issues
    Some libraries return complex objects (e.g., MongoDB’s ObjectId or Prisma’s model instances) that aren’t plain objects.

How to Fix the “Only Plain Objects” Warning

Now that you know why the warning happens, let’s fix it! Here are step-by-step solutions for the most common scenarios, complete with code examples.

Solution 1: Convert Non-Serializable Data to Plain Objects

The easiest fix is to transform your data into a plain object before passing it to the Client Component. Here’s how:

Example: Fixing a Date Object

// Server Component (page.js)
async function Page() {
  const user = {
    name: "John",
    createdAt: new Date().toISOString(), // Convert Date to string
  };
  return <ClientComponent user={user} />;
}

// Client Component (ClientComponent.js)
'use client';
export default function ClientComponent({ user }) {
  return <div>{user.name} joined on {user.createdAt}</div>;
}

By converting new Date() to a string with toISOString(), the data becomes JSON-serializable, and the warning disappears.

Example: Removing Functions

// Server Component (page.js)
async function Page() {
  const user = {
    name: "John",
    // No functions here!
  };
  return <ClientComponent user={user} />;
}

If the Client Component needs logic, move the function to the Client Component itself:

// Client Component (ClientComponent.js)
'use client';
export default function ClientComponent({ user }) {
  const sayHello = () => "Hello!";
  return <div>{user.name} says {sayHello()}</div>;
}

Solution 2: Handle Complex Objects from APIs or Databases

If you’re fetching data from an API or database (like MongoDB or Prisma), the returned objects might include non-serializable fields. You need to “clean” the data first.

Example: Cleaning MongoDB Data

MongoDB’s ObjectId and Date fields often cause issues. Here’s how to fix it:

// Server Component (page.js)
import { MongoClient } from 'mongodb';

async function Page() {
  const client = await MongoClient.connect('mongodb://localhost:27017');
  const db = client.db('mydb');
  const rawUser = await db.collection('users').findOne({ name: "John" });

  // Convert to plain object
  const user = {
    name: rawUser.name,
    createdAt: rawUser.createdAt.toISOString(), // Convert Date
    id: rawUser._id.toString(), // Convert ObjectId to string
  };

  return <ClientComponent user={user} />;
}

For Prisma, you can use JSON.parse(JSON.stringify(data)) as a quick fix, but be careful—it’s not always the most efficient:

// Server Component (page.js)
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function Page() {
  const rawUser = await prisma.user.findFirst();
  const user = JSON.parse(JSON.stringify(rawUser)); // Converts to plain object
  return <ClientComponent user={user} />;
}

Solution 3: Move Logic to Client Components

If your Server Component is trying to pass functions or complex logic, consider moving that logic to the Client Component. Server Components are meant for fetching data and rendering static content, while Client Components handle interactivity.

Example: Moving Event Handlers

// Server Component (page.js)
async function Page() {
  const user = { name: "John" };
  return <ClientComponent user={user} />;
}

// Client Component (ClientComponent.js)
'use client';
export default function ClientComponent({ user }) {
  const handleClick = () => alert(`Hi, ${user.name}!`);
  return <button onClick={handleClick}>Say Hi</button>;
}

Solution 4: Use use Hook for Client-Side Data Fetching

If you need complex data in a Client Component, you can fetch it directly in the Client Component using the use hook (available in Next.js 13+). This avoids passing non-serializable data altogether.

// Server Component (page.js)
async function Page() {
  return <ClientComponent />;
}

// Client Component (ClientComponent.js)
'use client';
import { use } from 'react';

async function fetchUser() {
  const res = await fetch('/api/user');
  return res.json();
}

export default function ClientComponent() {
  const user = use(fetchUser());
  return <div>{user.name}</div>;
}

Solution 5: Use a Serialization Library

For advanced cases, you can use libraries like superjson to handle complex data types. superjson serializes things like Date, Map, and Set into a format that Next.js can handle.

Example: Using superjson

// Server Component (page.js)
import superjson from 'superjson';

async function Page() {
  const user = {
    name: "John",
    createdAt: new Date(),
  };
  const serializedUser = superjson.stringify(user);
  return <ClientComponent serializedUser={serializedUser} />;
}

// Client Component (ClientComponent.js)
'use client';
import superjson from 'superjson';

export default function ClientComponent({ serializedUser }) {
  const user = superjson.parse(serializedUser);
  return <div>{user.name} joined on {user.createdAt.toString()}</div>;
}

Note: Install superjson with npm install superjson and ensure it’s compatible with your Next.js version.


Best Practices to Avoid the Warning

To keep your Next.js app warning-free, follow these best practices:

  1. Always Use Plain Objects for Props
    Before passing props from a Server Component, double-check that they’re plain objects or arrays. Use tools like JSON.stringify() to test serializability.
  2. Keep Server Components Lean
    Server Components should focus on fetching data and rendering static content. Move interactivity (like event handlers) to Client Components.
  3. Clean API/Database Data
    Always transform API or database responses into plain objects before passing them to Client Components.
  4. Use TypeScript for Safety
    TypeScript can help catch non-serializable props at compile time. Define interfaces for your props to ensure they’re plain objects.
  5. Test Hydration
    After fixing the warning, test your app to ensure Client Components hydrate correctly. Use Next.js’s dev mode (npm run dev) to spot issues.

Debugging the Warning

If you’re still seeing the warning, here’s how to track down the culprit:

  1. Check the Stack Trace
    The warning usually includes a stack trace in your terminal or browser console. Look for the file and line number where the prop is being passed.
  2. Log the Props
    Add console.log(props) in your Client Component to inspect what’s being passed. Look for non-serializable types like functions or Dates.
  3. Simplify the Data
    Temporarily simplify the props being passed (e.g., { name: "Test" }) to isolate the issue.
  4. Use Next.js Dev Tools
    Next.js’s development mode highlights hydration errors and warnings. Run npm run dev and check the console.

SEO Benefits of Fixing This Warning

Fixing the “Only plain objects” warning isn’t just about clean code—it’s also great for SEO! Here’s why:

  • Faster Page Loads: Properly serialized props mean smoother hydration, which improves your site’s Core Web Vitals (like LCP and FCP).
  • Better Crawling: Googlebot loves error-free pages. Fixing this warning ensures your pages render correctly for search engines.
  • Improved User Experience: A bug-free app keeps users on your site longer, reducing bounce rates and boosting rankings.

To maximize SEO, also:

  • Use descriptive <title> and <meta> tags with your focus keyword (“Next.js only plain objects warning”).
  • Add internal links to related pages (e.g., a guide on Next.js Server Components).
  • Optimize images with next/image for faster load times.

FAQs About the “Only Plain Objects” Warning

What is a plain object in JavaScript?

A plain object is a simple key-value structure, like { name: "John", age: 30 }. It doesn’t include functions, Dates, or complex types like Map or Set.

Can I ignore this warning?

Not recommended! It can cause hydration errors, broken features, or performance issues in your Next.js app.

Does this warning only happen in Next.js?

Yes, it’s specific to Next.js’s App Router, which splits components into Server and Client Components and requires JSON-serializable props.

How do I know if my props are serializable?

Test them with JSON.stringify(props). If it throws an error, your props aren’t serializable.


Conclusion: Master Next.js with Confidence

The “Only plain objects can be passed to Client Components from Server Components” warning might seem intimidating, but it’s a sign that you’re diving into the exciting world of Next.js’s App Router! By understanding why this warning happens and following the solutions above, you can build faster, more reliable, and SEO-friendly web apps in 2025.

Whether you’re converting Dates to strings, cleaning database data, or moving logic to Client Components, these fixes will make your Next.js apps shine. So, go ahead—squash that warning, test your app, and keep exploring the awesome possibilities of Next.js!


Resources

Leave a Comment