| name | nextjs |
| description | Next.js 16 App Router patterns and best practices for this project |
Next.js 16 Skill
Overview
This project uses Next.js 16.1.4 with the App Router, TypeScript, and Tailwind CSS. Next.js 16 brings significant performance improvements with Turbopack as the default bundler and built-in React Compiler support.
Project Configuration
Detected Version: Next.js 16.1.4
Router: App Router (default)
Language: TypeScript 5.x
Styling: Tailwind CSS 4.x
Node.js: 20.9+ required
Key Files:
next.config.ts - Next.js configuration (TypeScript)
src/app/layout.tsx - Root layout with metadata
src/app/page.tsx - Home page
src/app/globals.css - Global styles
tsconfig.json - TypeScript configuration with Next.js plugin
App Router Fundamentals
File-Based Routing
src/app/
โโโ layout.tsx # Root layout (required)
โโโ page.tsx # Home route (/)
โโโ globals.css # Global styles
โโโ favicon.ico # Site favicon
โโโ tasks/ # Example nested route
โโโ page.tsx # /tasks route
Special Files
| File | Purpose | Required |
|---|
layout.tsx | Shared UI for route segment | Yes (root) |
page.tsx | Route UI, makes route publicly accessible | Yes |
loading.tsx | Loading UI with Suspense | No |
error.tsx | Error UI boundary | No |
not-found.tsx | 404 UI | No |
Server vs Client Components
Server Components (Default)
By default, all components in the App Router are Server Components:
export default function Home() {
return <div>Server-rendered content</div>;
}
Benefits:
- Zero JavaScript sent to client
- Direct access to backend resources
- Better SEO
- Faster initial page load
Client Components
Use 'use client' directive when you need:
- React hooks (
useState, useEffect, etc.)
- Event handlers (
onClick, onChange, etc.)
- Browser APIs
- Interactive UI
'use client';
import { useState } from 'react';
export default function TaskInput() {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
Component Boundary Best Practice
import TaskList from '@/components/TaskList';
export default function Home() {
return (
<main>
<h1>Task Manager</h1>
<TaskList /> {/* Client interactivity isolated here */}
</main>
);
}
Rule: Keep Server Components as far up the tree as possible, only use Client Components where interactivity is needed.
Metadata API
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Task Manager',
description: 'A simple task management app',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Dynamic Metadata:
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const task = await getTask(params.id);
return { title: task.description };
}
Common Patterns (2026)
1. Project Structure
src/
โโโ app/ # App Router pages
โ โโโ layout.tsx
โ โโโ page.tsx
โ โโโ globals.css
โโโ components/ # React components
โ โโโ ui/ # Generic UI components
โ โโโ layout/ # Layout components
โ โโโ features/ # Feature-specific components
โโโ lib/ # Utilities and types
โโโ types.ts
โโโ utils.ts
Best Practice: Use @/ import alias (configured in tsconfig.json):
import { Task } from '@/lib/types';
import TaskInput from '@/components/TaskInput';
2. Font Optimization
Next.js 16 includes automatic font optimization with next/font:
import { Geist, Geist_Mono } from 'next/font/google';
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
});
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
{children}
</body>
</html>
);
}
3. Image Optimization
import Image from 'next/image';
<Image
src="/task-icon.png"
alt="Task icon"
width={24}
height={24}
priority // For above-the-fold images
/>
4. CSS and Tailwind
@tailwind base;
@tailwind components;
@tailwind utilities;
<div className="flex min-h-screen items-center justify-center bg-zinc-50">
<main className="max-w-3xl w-full px-4">
{/* Content */}
</main>
</div>
Performance Optimizations (Next.js 16)
1. Turbopack (Default)
Turbopack is now the default bundler in Next.js 16:
- 2-5ร faster production builds
- Up to 10ร faster Fast Refresh
- No configuration needed - works out of the box
Enable filesystem caching for even faster rebuilds:
export default {
experimental: {
turbopackFileSystemCacheForDev: true,
},
};
2. React Compiler (Built-in)
React Compiler is stable in Next.js 16:
- Automatic memoization - no need for manual
useMemo, useCallback
- Reduces re-renders automatically
- Enabled by default for new projects
const filteredTasks = tasks.filter(task => {
if (filter === 'active') return !task.completed;
if (filter === 'completed') return task.completed;
return true;
});
3. Async Request APIs (Stable)
export default async function TasksPage() {
const tasks = await fetchTasks();
return <TaskList tasks={tasks} />;
}
Best Practices from Research (2026)
1. Separation of Concerns
- Server Components: Data fetching, backend logic
- Client Components: User interactions, state management
- Shared Components: UI components used in both
2. TypeScript First
- Always use TypeScript for better type safety
- Use the TypeScript plugin for advanced type-checking
- Leverage TypeScript 5.x features
3. Production Checklist
Before deploying:
- โ
Run
npm run build to check for build errors
- โ
Enable TypeScript strict mode (
strict: true in tsconfig.json)
- โ
Test responsive design (mobile-first)
- โ
Verify accessibility (keyboard navigation, ARIA)
- โ
Check bundle size with
npm run build
4. Development Workflow
npm run dev
npm run build
npm run start
npm run lint
Common Pitfalls (2026)
โ Don't: Mix Server and Client concerns
'use client';
export default function BadComponent() {
const data = await fetch('/api/tasks');
return <div>{data}</div>;
}
โ
Do: Separate concerns properly
async function TasksPage() {
const tasks = await fetchTasks();
return <TaskList tasks={tasks} />;
}
'use client';
function TaskList({ tasks }: { tasks: Task[] }) {
const [filter, setFilter] = useState('all');
}
โ Don't: Use 'use client' everywhere
'use client';
export default function StaticContent() {
return <div>Just static content</div>;
}
โ
Do: Default to Server Components
export default function StaticContent() {
return <div>Static content</div>;
}
โ Don't: Import Client Components in Server Components carelessly
import ClientComponent from './ClientComponent';
export default function Page() {
return <ClientComponent callback={() => console.log('test')} />;
}
โ
Do: Only pass serializable props
export default function Page() {
return <ClientComponent data={{ id: 1, name: 'Task' }} />;
}
References