gotchatypescriptnextjsMajor
Client boundary serialization: passing data from Server to Client Components
Viewed 0 times
Next.js 13+ with App Router and React Server Components
serializationclient boundaryServer to Client propsDate serializationfunction propsRSC payload
Error Messages
Problem
A Server Component passes a complex object (Date, Map, class instance, function) as props to a Client Component and gets an error about non-serializable values. Only JSON-serializable data can cross the Server/Client boundary.
Solution
Only pass serializable data across the boundary; convert complex types before passing:
// BAD: passing non-serializable values
const user = await db.user.findUnique({ where: { id } });
return <UserProfile user={user} onUpdate={handleUpdate} />;
// Error: handleUpdate is a function — can't be serialized
// Error: user.createdAt is a Date — serialize to string
// GOOD: serialize at the boundary
return (
<UserProfile
user={{
id: user.id,
name: user.name,
createdAt: user.createdAt.toISOString(), // Date to string
}}
// For callbacks, use a Server Action instead of a function prop:
/>
);
// actions.ts
'use server';
export async function updateUser(formData: FormData) { / ... / }
// UserProfile.tsx
'use client';
import { updateUser } from '@/app/actions';
export function UserProfile({ user }) {
return <form action={updateUser}>...</form>;
}
// Serializable: string, number, boolean, null, plain objects, arrays, Uint8Array
// NOT serializable: functions, class instances, Date objects, Map, Set, Symbol
// BAD: passing non-serializable values
const user = await db.user.findUnique({ where: { id } });
return <UserProfile user={user} onUpdate={handleUpdate} />;
// Error: handleUpdate is a function — can't be serialized
// Error: user.createdAt is a Date — serialize to string
// GOOD: serialize at the boundary
return (
<UserProfile
user={{
id: user.id,
name: user.name,
createdAt: user.createdAt.toISOString(), // Date to string
}}
// For callbacks, use a Server Action instead of a function prop:
/>
);
// actions.ts
'use server';
export async function updateUser(formData: FormData) { / ... / }
// UserProfile.tsx
'use client';
import { updateUser } from '@/app/actions';
export function UserProfile({ user }) {
return <form action={updateUser}>...</form>;
}
// Serializable: string, number, boolean, null, plain objects, arrays, Uint8Array
// NOT serializable: functions, class instances, Date objects, Map, Set, Symbol
Why
Props crossing the Server/Client boundary are serialized to JSON (or RSC payload format). Functions, class instances, Dates (as objects), Maps, Sets, and Symbols cannot be serialized. Next.js enforces this at build/runtime to prevent impossible states.
Gotchas
- Passing functions as props to Client Components is the most common violation — use Server Actions instead
- Date objects are serialized as strings in RSC payloads — reconstruct with new Date(dateString) in the client
- Prisma model instances are class instances — spread them into plain objects before passing
- Arrays of serializable items are fine; arrays of class instances are not
Code Snippets
Serializing DB result for Client Component
// Convert Prisma result to plain object
const rawUser = await db.user.findUniqueOrThrow({ where: { id } });
const user = {
id: rawUser.id,
name: rawUser.name,
createdAt: rawUser.createdAt.toISOString(), // Date -> string
};
return <ClientUserCard user={user} />;Context
When passing data from Server Components down to Client Components as props
Revisions (0)
No revisions yet.