stackademic

The leading education platform for anyone with an interest in software development.

Next.js Server Components

Render on the server by default with async data fetching and zero client JS

Overview

Server Components run only on the server. They can be async, access databases directly, and do not ship component logic to the browser. Use them by default; add Client Components only when you need interactivity.

Syntax / Usage

// Server Component (default — no directive)
async function ProductList() {
  const products = await db.products.findMany()
  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  )
}

// Fetch in Server Component
async function Page() {
  const res = await fetch('https://api.example.com/posts', {
    next: { revalidate: 60 },
  })
  const posts = await res.json()
  return <PostList posts={posts} />
}

Server Components can import Client Components as children, but not vice versa directly.

Examples

Stream data with Suspense:

import { Suspense } from 'react'

export default function Page() {
  return (
  <Suspense fallback={<Skeleton />}>
    <SlowData />
  </Suspense>
  )
}

async function SlowData() {
  const data = await fetchAnalytics()
  return <Chart data={data} />
}

Pass server data to a client form:

// Server
export default async function EditPage({ params }) {
  const user = await getUser(params.id)
  return <EditForm user={user} />
}

// Client child receives serialized props
'use client'
function EditForm({ user }: { user: User }) { /* ... */ }

Common Mistakes

  • Using hooks (useState, useEffect) in Server Components
  • Passing non-serializable props (functions, class instances) to Client Components
  • Fetching the same data in both layout and page without caching/deduping
  • Marking entire trees 'use client' when only a leaf needs it

See Also

client-components app-router routing api-routes