Course outline

React / Performance and trustworthy boundaries / Lesson 16

Server, client, and framework boundaries

Distinguish execution environments, serialized data, and framework-owned server features without treating a client directive as authorization.

About 4 min readContent reviewed
On this page

Lesson goals

  • Separate three architectural concepts
  • Transfer only a deliberate public view
  • Treat server actions as trusted entry points

Separate three architectural concepts

Client rendering executes interactive component logic in the browser. SSR can produce initial HTML for hydration. React Server Components run in a separate server environment and can supply a representation that composes with client components through a supported integration. These concepts overlap in frameworks but are not synonyms. A Client Component can participate in initial server-rendered HTML, so the word client does not universally mean “never evaluated before browser execution.” Follow the chosen framework’s documented module graph and rendering model. React’s component APIs alone do not provide a deployable server, router, database layer, or security policy.

A module boundary determines what ships

In an RSC-capable setup, a use client directive establishes a boundary in the module graph for client code and its relevant imports. It is not a per-element toggle or a browser security sandbox. Values crossing from server to client must satisfy the integration’s supported serialization contract, and secrets must not cross that boundary simply because they came from a server component. Keep server-only capabilities behind an enforced server module boundary. A bundler that merely parses a string directive does not implement RSC semantics; the framework and compatible tooling must actually support them.

Transfer only a deliberate public view

The first example builds a small public record projection from a synthetic server-shaped object. It selects only the title and seat count, then renders that public view. This is ordinary shared JavaScript in the teaching host, not a security-enforced server module or a claim that the browser cannot inspect the original fixture. A real server projection must occur before serialization and client bundling, with access checks at the trusted boundary. Returning an entire database record and hiding fields in JSX still delivers those fields to the client. Data minimization and authorization complement one another rather than replacing each other.

jsx Component module — requires the course React host
export function publicView(record) { return { title: record.title, seats: record.seats }; }
const view = publicView({ title: "Alpha workshop", seats: 8, internalNote: "Synthetic private field" });
export default function App() { return <main><h1>{view.title}</h1><p>Seats: {view.seats}</p></main>; }
Expected output
Alpha workshop
Seats: 8

The projection illustrates a public data shape. Because this entire fixture is bundled locally, it demonstrates selection rather than enforcing secrecy.

Mark interactive ownership explicitly

The second module includes a use client directive and a local stateful counter. In an appropriate React Server Components framework, that directive identifies the client-side module boundary; in the isolated React 18 test host it is only an inert directive string, so the test verifies the counter’s shared client behavior rather than RSC integration. State Hooks, event handlers, and browser-only APIs belong in suitable client code. Server components can pass public data and supported references according to the integration’s rules. Do not invent a generic rule that arbitrary functions or class instances can cross the boundary unchanged.

jsx Component module — requires the course React host
"use client";
import { useState } from "react";
export default function App() { const [count, setCount] = useState(0); return <main><h1>Client interaction</h1><button type="button" onClick={() => setCount(c => c + 1)}>Count {count}</button></main>; }
Expected output
Initial button: Count 0. After click: Count 1.

An RSC framework interprets the directive. The local shared-API host only verifies the interactive component and does not claim a server-component build.

Treat server actions as trusted entry points

Server Functions and framework action features expose callable server behavior under specific integration rules. A server directive is not an authorization check. Validate inputs, authenticate the caller, authorize the resource operation, limit work, and define retry and idempotency behavior at that boundary. React 19 stabilizes Server Components for application use, while official documentation notes that underlying framework or bundler integration APIs can change between minor versions and need version coordination. Do not build a custom RSC transport from undocumented internals in a beginner application. Use a supported framework and its reviewed deployment guidance, and test the complete boundary separately from client-only component examples.

Common errors and fixes

A secret appears in the client bundle

Why it happens
Server-origin data crossed the boundary before being minimized.
How to fix it
Project and authorize on the real server before delivery.
Prevent it next time
Review serialized props and imports.

A directive is assumed to implement RSC by itself

Why it happens
The build host lacks the framework integration.
How to fix it
Use supported coordinated tooling and document its behavior.
Prevent it next time
Distinguish syntax parsing from integration testing.

A server action trusts its UI caller

Why it happens
A server directive was mistaken for authorization.
How to fix it
Validate and authorize every exposed operation.
Prevent it next time
Test direct unauthorized entry attempts in isolated fixtures.

Check your understanding

1. Why can hiding an internal field in JSX fail to protect it?

Show worked solution

If the full object was serialized or bundled into the browser, the user can inspect it regardless of the visible markup. Remove nonpublic data at the trusted server projection and enforce access before delivery. Presentation logic is not a confidentiality boundary.

2. What does the local use client example prove and what does it leave to framework testing?

Show worked solution

It proves the counter’s client behavior under the installed React host. It does not prove module splitting, server serialization, action transport, SSR coordination, or authorization. Those require the selected framework’s actual build and server integration tests with compatible versions.

Key takeaways

  • SSR, RSC, and client rendering are distinct.
  • Module directives are not security checks.
  • Verify framework integration separately.

Official references