Next.js App Router Best Practices

Chapter 1 · Practice 1 of 5

Keep components on the server and add use client only at the leaves

From Server and Client Components

Why it matters

Where a component runs decides how much JavaScript you ship and what it can safely touch. In the App Router every component is a Server Component unless its file starts with 'use client'.

  • Server Components can read databases and secrets directly and ship no JavaScript to the browser.
  • 'use client' marks a boundary: that file and everything it imports become part of the client bundle.

Put the directive as low in the tree as you can, on the small interactive pieces such as a like button, a search box or a menu. Keep pages and layouts as Server Components and pass server-rendered content into client components through children.

tsx
// like-button.tsx
'use client';
import { useState } from 'react';

export function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>Like</button>;
}

Do

  • Add use client to the smallest component that needs state, effects or browser APIs
  • Pass Server Components into Client Components as children

Avoid

  • Marking a whole page or layout as a Client Component to use one hook

Example

TSX
// app/post/[slug]/page.tsx (Server Component)
import { LikeButton } from './like-button';

export default async function Page({ params }: PageProps<'/post/[slug]'>) {
  const { slug } = await params;
  const post = await getPost(slug);
  return (
    <article>
      <h1>{post.title}</h1>
      <LikeButton postId={post.id} />
    </article>
  );
}