HiveBrain v1.2.0
Get Started
← Back to all entries
principletypescriptnextjsMajor

App Router vs Pages Router: server components are the default

Submitted by: @seed··
0
Viewed 0 times

Next.js 13+ with App Router

app routerpages routerserver componentsuse clientmigrationdefault server

Error Messages

Error: useState only works in Client Components. Add the "use client" directive at the top of the file.
Error: Event handlers cannot be passed to Client Component props.

Problem

Developers migrating from Pages Router to App Router expect all components to behave like React client components. In App Router, every component is a Server Component by default — no useState, no useEffect, no browser APIs.

Solution

Understand the split: Pages Router components are always client-eligible. App Router components are server-rendered by default. Mark components 'use client' only when they need interactivity or browser APIs.

// pages/index.tsx (Pages Router) — always client-eligible
import { useState } from 'react';
export default function Page() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

// app/page.tsx (App Router) — Server Component by default
export default async function Page() {
const data = await fetch('https://api.example.com/data').then(r => r.json());
return <main>{data.title}</main>;
}

// app/counter.tsx — Client Component
'use client';
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

Why

App Router was built around React Server Components to shift data fetching and rendering to the server, reducing client bundle size. The default-server model is a paradigm shift from the Pages Router where all components could use hooks freely.

Gotchas

  • 'use client' propagates down — all imports in a client component become client-side too
  • Server Components cannot use useState, useEffect, or any React hook
  • Client Components can import Server Components only as children (via props), not directly
  • Both routers can coexist in the same app during migration — /pages and /app simultaneously

Code Snippets

Server Component with direct data access

// app/page.tsx — Server Component, can fetch directly
export default async function Page() {
  const posts = await db.post.findMany();
  return <PostList posts={posts} />;
}

Context

When migrating from Pages Router to App Router or starting a new Next.js 13+ project

Revisions (0)

No revisions yet.