client-server-boundary
Client-Server Boundary
Concept of the skill
The client-server boundary is the line in a unified codebase where execution context changes between a server runtime and a client runtime. The server runtime can hold secrets, reach databases, read files, and enforce authority. The client runtime is a browser or other public caller that can read any code and data shipped to it and can send arbitrary requests back.
Anything that crosses this line is serialized. It is encoded by a wire format on one side and decoded into a value on the other. The active format matters: JSON, structured clone, React Server Component payloads, React Server Function arguments and returns, SvelteKit server-load data, and FormData are related but not interchangeable. The boundary is governed by three properties:
- Serialization - only values the active serializer supports can cross. Ordinary closures, rich class instances, host-bound objects, DOM nodes, request/response objects, ORM entities, and prototype-dependent domain objects should not cross.
- Direction - server -> client sends payloads the client can read; client -> server sends arguments, form data, cookies, headers, URL params, search params, and request bodies that the server must treat as adversarial.
- Trust - the server trusts server-authoritative state, the client may trust server-sent data as UI input, and the server trusts nothing the client sends until it has parsed, validated, authenticated, authorized, and rate-limited it.
Modern frameworks make this boundary syntactically visible through directives such as 'use client' and 'use server', guard imports such as import 'server-only' and import 'client-only', and file conventions such as SvelteKit's .server suffix, $lib/server directory, and +page.server.js / +layout.server.js load files. These marks do not invent the boundary. They expose an old boundary inside a shared module tree where it is otherwise easy to forget.
Coverage
This skill covers the serialization and trust transition between server and client code: directive semantics, import-graph reachability, what values may cross in common formats, how React Server Components and Server Functions encode values, why client-to-server calls are endpoint calls, how server-only code leaks into client bundles, how server-to-client payloads leak secrets or raw records, how URL-derived values remain client input, and how TypeScript stops at the runtime boundary.
It is framework-portable, but it uses React Server Components and Next.js App Router as the modern canonical example because those systems put server and client modules in one file tree. SvelteKit is the compact cross-checking example: .server files and $lib/server modules are rejected from browser-running import graphs, while server load files (+page.server.js, +layout.server.js) return data that is serialized for the browser.