Composition Patterns

Push Client Components to the Leaves

Keep pages and layouts on the server; make only the interactive leaf a Client Component. A search bar in a layout should not turn the whole layout into client code.

// app/layout.tsx (server)
import SearchBar from '@/components/SearchBar'; // 'use client'
import CategoryMenu from '@/components/CategoryMenu'; // server, reads DB

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <header>
          <CategoryMenu />
          <SearchBar />
        </header>
        {children}
      </body>
    </html>
  );
}

Providers Wrap Server Children

Context providers need 'use client'. Wrap them in a small client file and pass the server tree as children, so the pages stay Server Components:

// app/providers.tsx
'use client';

import { ThemeProvider } from '@/components/theme';
import { CartProvider } from '@/components/cart';

export default function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider>
      <CartProvider>{children}</CartProvider>
    </ThemeProvider>
  );
}

// app/layout.tsx (server)
// <body><Providers>{children}</Providers></body>

Third-party Client Libraries

A library component that uses hooks but has no 'use client' (for example an older carousel) fails in a Server Component. Re-export it from a client file:

// components/Carousel.tsx
'use client';

export { default } from 'react-slick';

Rule of Thumb

PatternOK?
Server imports ClientYes
Client receives Server as children / propsYes
Client imports ServerNo — it becomes client code (and fails if it is async or server-only)