Engineering

Understanding Data Serialization in Next.js

A technical explanation of how data serialization works in Next.js, covering server components, client components, and data passing.

Understanding Data Serialization in Next.js: Why Props Are Visible in Page Source

Executive Summary

When inspecting a production Next.js site, developers often discover a block of JSON data embedded in the HTML source—typically within a __NEXT_DATA__ script (Pages Router) or an RSC payload (App Router). While this may look like a data leak, it is a deliberate architectural requirement for modern React frameworks.

What Is This Concept Called?

This behavior is fundamental to Isomorphic (or Universal) Rendering. It involves:

  • State Serialization: Converting server-side data into a JSON format for transport.
  • Hydration: The process that React in the browser reads the server-rendered HTML and the serialized data to make the page interactive.

Why Is This Necessary?

1. Hydration Requirements

React must ensure the UI generated on the server exactly matches the UI generated on the client. Without the original props, the client-side React cannot reconstruct the component tree accurately, leading to "Hydration Mismatch" errors.

2. Performance and UX

By embedding data in the HTML, the browser avoids making an extra API request immediately after load. Content is visible instantly for SEO, and interactivity begins as soon as the JavaScript loads.

3. Client-Side Navigation

Next.js uses this serialized data to handle transitions between pages without requiring a full browser refresh.

How It Works (Under the Hood)

Pages Router (getStaticProps / getServerSideProps)

The server executes the> tag. The client reads this script to initialize the application state.

App Router (Server Components)

Server Components execute only on the server. Their output is streamed as a React Server Component (RSC) payload. Unlike the Pages Router, only data explicitly passed to "Client Components" ('use client') is serialized and sent to the browser.

Security Implications: Is This a Risk?

No, provided it is used correctly.

Next.js does not "leak" data; it transmits exactly what you provide to your components. If sensitive information appears in the source, it is because that data was included in the return value of your server-side functions.

Key Constraints:

  • Visibility is Mandatory: If the browser needs the data to render a component, that data is technically public to the end-user.
  • Obfuscation is Not Security: Minifying or encoding JSON does not prevent a user from reading it; it only makes it slightly more difficult to find.

Best Practices for Production

  • Treat Props as Public: Assume any data returned from getServerSideProps or passed to a Client Component is public information.
  • Prune Data Aggressively: Never pass entire database rows. Manually select only the specific fields required for the UI.
  • Use Server Components: Use the App Router to keep sensitive logic on the server. Only "bridge" the necessary UI data to Client Components.
  • Audit Your Payloads: Periodically check the "View Source" of your production site to see exactly what is being sent to the client.

Summary Comparison Table

DoDon't
Use Server Components to hide logicPass full database records to the client
Audit production page sourceRely on minification for security
Strip unused fields from API responsesInclude internal flags in props
Keep secrets in .env (Server-only)Assume data is hidden if it's in a script
Resume