Pattern 1: Server wraps Client (children)
Most common shape. A Server Component fetches data and renders a Client Component, passing other Server Components as children. The client wrapper handles interactivity; the children stay server-rendered.
Pattern 2: Context providers
React Context requires a Client Component (it uses hooks). Build a thin 'use client' provider and place it inside the root layout. Everything else can stay server.
Pattern 3: Slots via props
For more deliberate composition (e.g., a modal that needs a header, body, and footer rendered server-side), accept multiple ReactNode props instead of a single children. The Client Component arranges them but doesn't render them.
Give an interactive shell behavioral props and server-rendered slots. A modal can own onClose while receiving header, body, and footer as React nodes. A provider can stay thin while its children remain server-authored. This keeps interaction and content ownership separate. A root provider does not automatically turn server children into client modules, but a frequently changing context still rerenders every client consumer beneath it. Split providers by lifetime and update frequency rather than making one global bag of state.
Build a tab or modal whose content modules are never imported by the client shell. Inspect the bundle, then move the provider between root and a smaller subtree and measure the rerender scope. Composition should make the boundary visible, not merely hide imports.