
Master the Hybrid Header: Building a Dynamic Navigation Menu in Next.js 15
In this second tutorial of our Next.js Mastery series, we are moving beyond "Hello World" to build a real-world, database-driven navigation menu. We will explore how to combine Server Components (for database fetching) and Client Components (for interactivity) to create a high-performance Header.
1. The File Structure
For a clean and professional architecture, we separate our logic into a dedicated component folder. This makes our code easier to manage as the project grows.
Plaintext
src/
└── components/
└── Header/
└── Menu/
├── Menu.jsx (Server Component - Data Fetching)
└── MenuClient.jsx (Client Component - UI & Interactivity)
2. The Code Explanation
Phase 1: The Server Component (Menu.jsx)
This is the entry point. In Next.js, components are Server Components by default.
Why do we do this? We want to fetch our categories directly from the database using Prisma. Doing this on the server means the database credentials never leave the server, making it highly secure and fast.
JavaScript
import prisma from "@/lib/prisma";
import MenuClient from './MenuClient';
export default async function Menu() {
// 1. Database Fetching: Getting live categories from Prisma
const categories = await prisma.category.findMany({
orderBy: { name: 'asc' },
});
// 2. Passing data to the Client Component
return <MenuClient categories={categories} />;
}
Phase 2: The Client Component (MenuClient.jsx)
We use the 'use client'; directive here because we need browser-only features like useState (for the mobile toggle) and usePathname (to highlight the active link).
How it works:
Active Link Highlighting: It uses
usePathname()to check which page the user is on. If the current URL matches the link, it applies a bold style (text-gray-900 font-semibold).Mobile Interactivity: It manages an
openstate. When you click the "Hamburger" icon, it toggles the mobile menu visibility using Tailwind CSS transitions.Data Rendering: it maps through the
categoriesarray received from the server to generate dynamic links.
3. Why This Architecture? (The "Why" and "How")
The Hybrid Approach
In Next.js, we don't want everything to be a Client Component because it makes the JavaScript bundle larger. By using this hybrid approach:





