Building Scalable Full-Stack Apps with Next.js 14
A deep dive into the App Router, Server Components, and how to architect production-grade applications that scale.
Param Panwar November 15, 2024 2 min read
Introduction
Next.js 14 introduced the App Router as a stable feature, completely changing how we think about routing, data fetching, and component architecture. After building several production apps with it, here's what I've learned.
Server Components vs Client Components
The most important mental model shift is understanding when code runs.
// Server Component — runs on the server, no interactivity
async function UserProfile({ id }: { id: string }) {
const user = await db.users.findById(id); // direct DB access!
return <div>{user.name}</div>;
}
// Client Component — runs in the browser, can have state
'use client';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
The golden rule: default to Server Components, opt into Client Components only when you need browser APIs, event listeners, or React hooks.
Data Fetching Patterns
Parallel Fetching
async function Dashboard() {
// These run in parallel — much faster
const [user, posts, analytics] = await Promise.all([
getUser(),
getPosts(),
getAnalytics(),
]);
return <>{/* render everything */}</>;
}
Streaming with Suspense
import { Suspense } from 'react';
function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<SlowDataComponent /> {/* streams in when ready */}
</Suspense>
</div>
);
}
Conclusion
The mental model shift is steep, but the performance gains and DX improvements are worth it. Start with the App Router for new projects and migrate incrementally for existing ones.
Written by
Param Panwar