Next.js Curriculum
MediumSecurity100% Free30 min read

Preventing Data Leaks with server-only & React Taint APIs

The 30-Second Interview Answer

Data leaks in React Server Components occur when sensitive server-side secrets or raw database records are accidentally imported by Client Components or passed across component boundaries. Next.js prevents code leaks using the "server-only" package (build-time error). React further provides experimental Taint APIs (experimental_taintUniqueValue and experimental_taintObjectReference) to block sensitive runtime data values from being passed to client components.

Learning Objectives

Prevent server code from being bundled into client assets using the "server-only" package.

Explain the mechanism of React Taint APIs (taintUniqueValue and taintObjectReference).

Implement Data Access Layers (DAL) with explicit Data Transfer Objects (DTO) to strip secrets.

Audit bundles to ensure database connection strings and API keys never cross the wire.

Prerequisites & Background Knowledge
Client Component serializationReact Flight ProtocolBundler module resolution

Why Interviewers Care

A critical interview topic for enterprise frontend engineering. Demonstrates security vigilance against accidental credential leaks.

The Challenge

How do you prevent private backend code and sensitive data fields from leaking into client JavaScript bundles? Demonstrate using server-only and React Taint APIs alongside a Data Transfer Object (DTO) pattern.

Code Architecture & Implementation

1// lib/secrets.ts
2import 'server-only'; // Throws a BUILD ERROR if imported by any Client Component!
3
4export const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!;
5export const INTERNAL_API_TOKEN = process.env.INTERNAL_API_TOKEN!;
6
7export async function processStripePayment(amount: number) {
8 // Safe server logic...
9}

Architectural Explanation

Because Server Components and Client Components share the same TypeScript codebase, a developer might accidentally import a database utility or pass an entire user record { id, name, email, passwordHash, stripeCustomerId } as a prop to a Client Component. The server-only package halts the build if any client code imports the module. For runtime safety, React's Taint APIs register specific object references or strings with the React serializer; if that value is included in the Flight payload, React throws an error immediately.

Common Mistakes & Anti-Patterns

Passing raw database models directly to Client Components instead of projecting them into sanitized DTOs.

Assuming environment variables without NEXT_PUBLIC_ are always safe from client leaks (they are safe from inlining, but their values can still be passed as props!).

Forgetting that React Taint APIs are an additional defense layer and do not replace proper backend authorization.

Interview Follow-Up Traps

The interviewer asks: "If an environment variable does not have NEXT_PUBLIC_, can it ever reach the browser?" Yes! If a Server Component reads `process.env.SECRET` and passes it as `<ClientWidget secret={process.env.SECRET} />`, it will be sent to the browser in the RSC Flight JSON.

Frequently Asked Questions

What is the counterpart to "server-only"?

The counterpart is "client-only", which ensures a module (e.g. window/canvas helpers) is only ever executed in client environments.

No. `server-only` is an empty package resolved at build time; it introduces zero runtime overhead.

They are available as experimental features in React 19 / Next.js and are recommended as defense-in-depth in security-sensitive applications.