Next.js App Router: Pages, Layouts, Server Components, and Data Fetching
Learn how the Next.js App Router works with pages, layouts, dynamic routes, Server and Client Components, data fetching, loading states, metadata, and practical application structure.

Tools used: Next.js, VS Code, Node.js, npm, Git, GitHub
Prerequisites: Basic JavaScript, React components, JSX, props, and basic web development.
Next.js App Router: Pages, Layouts, Server Components, and Data Fetching
React gives you the tools to build user interfaces.
But a production application usually needs much more:
- routing
- layouts
- data fetching
- authentication
- metadata
- error handling
- loading states
- performance optimization
- server-side logic
- deployment
This is where Next.js becomes useful.
Next.js is a React framework designed for building full-stack web applications. Its App Router provides a file-system-based routing model and integrates features such as layouts, Server Components, data fetching, streaming, metadata, and more.
Quick answer: In the Next.js App Router, folders define route segments,
page.tsxcreates accessible pages,layout.tsxcreates shared UI, Server Components are the default, and Client Components are used when browser-side interactivity is required.
Next.js App Router at a Glance
| Feature | Purpose |
|---|---|
app/ | Main App Router directory |
page.tsx | Creates a route page |
layout.tsx | Shared UI around pages |
[id] | Dynamic route segment |
loading.tsx | Loading UI |
error.tsx | Route-level error UI |
not-found.tsx | Not-found UI |
| Server Component | Server-rendered component by default |
| Client Component | Interactive browser component |
Link | Client-side navigation |
| Metadata | SEO and social metadata |
What Is Next.js?
Next.js is built on React.
React handles the component layer.
Next.js adds application-level capabilities around it.
Think of the relationship like this:
Next.js can help you build complete applications rather than only individual UI components.
Why Use Next.js?
A React application can be built from many separate tools.
You may need to choose solutions for:
Routing
Data Fetching
Rendering
Code Splitting
SEO
Metadata
Server Logic
Error Handling
DeploymentNext.js provides conventions and built-in capabilities for many of these concerns.
The current Next.js documentation describes the framework as a way to build interactive, dynamic, and fast React applications while handling lower-level tooling for you.
App Router vs Pages Router
Next.js currently supports two routing systems:
- App Router
- Pages Router
The App Router is the newer routing model and supports newer React features such as Server Components. The Pages Router remains supported.
For new applications, this guide focuses on the App Router.
Creating a Next.js Application
A common way to start a new application is:
npx create-next-app@latest my-next-appThen:
cd my-next-appStart the development server:
npm run devOpen:
http://localhost:3000The official Next.js learning material currently uses create-next-app to bootstrap applications and also documents pnpm as a supported package-manager workflow.
Basic Next.js Project Structure
A typical App Router project might look like:
my-next-app/
├── app/
│ ├── layout.tsx
│ ├── page.tsx
│ └── globals.css
├── public/
├── package.json
├── next.config.ts
├── tsconfig.json
└── ...The important directory is:
app/This is where your routes and layouts are commonly defined.
How File-System Routing Works
Next.js uses folders and files to define routes.
Suppose you have:
app/
├── page.tsx
├── about/
│ └── page.tsx
└── contact/
└── page.tsxThe resulting routes are:
/
/about
/contactThe official App Router tutorial uses folders to create route segments and page.tsx files to make those routes accessible.
What Is page.tsx?
A page.tsx file represents the UI for a route.
For example:
app/
└── about/
└── page.tsxContent:
export default function AboutPage() {
return (
<main>
<h1>About</h1>
<p>Welcome to our application.</p>
</main>
);
}The page becomes available at:
/aboutWhat Is layout.tsx?
A layout provides shared UI around pages.
For example:
app/
├── layout.tsx
├── page.tsx
└── dashboard/
├── layout.tsx
└── page.tsxThe root layout can contain:
- HTML structure
- body
- navigation
- providers
- shared UI
- metadata
A nested dashboard layout can contain:
- sidebar
- dashboard navigation
- shared dashboard structure
Next.js uses layouts to share UI between multiple pages.
Root Layout
A basic root layout looks like:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}The root layout is required in an App Router application.
Nested Layouts
Suppose you have:
app/
├── layout.tsx
└── dashboard/
├── layout.tsx
├── page.tsx
└── settings/
└── page.tsxThe structure becomes:
The dashboard layout can remain around multiple dashboard routes.
This is particularly useful for applications with:
Dashboard
├── Overview
├── Users
├── Projects
├── Settings
└── ReportsDynamic Routes
Sometimes you don't know the route value ahead of time.
For example:
/products/123
/products/456
/products/789You can create:
app/
└── products/
└── [id]/
└── page.tsxThe [id] segment is dynamic.
A page can receive the route parameters and use them to load the appropriate data.
Example:
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return (
<main>
<h1>Product {id}</h1>
</main>
);
}Dynamic segments are one of the core routing patterns in the App Router.
Nested Dynamic Routes
You can combine static and dynamic segments.
app/
└── blog/
└── [slug]/
└── page.tsxThis can create URLs such as:
/blog/react-state-management
/blog/nextjs-routing
/blog/typescript-genericsThis pattern is particularly useful for:
- blogs
- products
- jobs
- documentation
- profiles
- learning resources
Route Groups
Sometimes you want to organize routes without adding a URL segment.
You can use parentheses:
app/
├── (marketing)/
│ ├── about/
│ └── pricing/
└── (dashboard)/
├── dashboard/
└── settings/The group name does not become part of the URL.
For example:
about/can still produce:
/aboutRoute groups can help organize larger applications.
Navigation with Link
For internal navigation, Next.js provides the Link component.
import Link from "next/link";
export default function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/projects">Projects</Link>
</nav>
);
}The official Next.js learning material recommends Link for navigation and explains that Next.js can optimize navigation through route-level code splitting and prefetching.
Link vs HTML Anchor
You can still use:
<a href="/about">About</a>But for internal Next.js navigation, prefer:
<Link href="/about">
About
</Link>This lets Next.js handle navigation using its routing system.
External websites can still use normal links:
<a
href="https://example.com"
target="_blank"
rel="noreferrer"
>
External Website
</a>Server Components
One of the most important concepts in the App Router is Server Components.
Components in the App Router are Server Components by default unless you explicitly opt into client-side behavior.
For example:
export default async function UsersPage() {
const response = await fetch(
"https://example.com/api/users"
);
const users = await response.json();
return (
<main>
{users.map((user: any) => (
<p key={user.id}>
{user.name}
</p>
))}
</main>
);
}The component can perform server-side work without turning the entire page into a Client Component.
Why Server Components Matter
Server Components can be useful for:
- fetching data
- accessing server-side resources
- keeping server-only logic away from the browser
- reducing client-side JavaScript
- rendering data-dependent UI
The goal isn't to make every component a Server Component because it sounds advanced.
Use server-side rendering capabilities where they make sense.
Client Components
Some components need browser-side interactivity.
Examples:
- click handlers
- browser APIs
- interactive forms
- local state
- effects
- certain client-only libraries
For these components, use:
"use client";at the top of the file.
Example:
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}Server vs Client Components
| Server Component | Client Component |
|---|---|
| Default in App Router | Requires "use client" |
| Can perform server-side work | Runs with browser-side interactivity |
| Good for data fetching | Good for interactive UI |
| Can access server-only resources | Can use browser APIs |
| No browser event handlers | Supports event handlers |
| Doesn't need client JS for its own interactivity | Adds client-side JavaScript |
A useful mental model:
Don't Make Everything a Client Component
A common beginner mistake is adding:
"use client";to every file.
You usually don't need it.
Ask:
Does this component need browser interaction?
↓
Yes → Client Component
↓
No
↓
Can it remain on the server?
↓
Yes → Server ComponentKeeping interactive code focused can make the application architecture easier to reason about.
Data Fetching
Next.js applications frequently need data.
For example:
Users
Products
Jobs
Posts
Orders
AnalyticsA Server Component can fetch data.
Example:
async function getJobs() {
const response = await fetch(
"https://example.com/api/jobs"
);
if (!response.ok) {
throw new Error("Failed to fetch jobs");
}
return response.json();
}
export default async function JobsPage() {
const jobs = await getJobs();
return (
<main>
{jobs.map((job: any) => (
<article key={job.id}>
<h2>{job.title}</h2>
<p>{job.company}</p>
</article>
))}
</main>
);
}Fetching Data from a Database
Server-side code can also work with a database.
Conceptually:
For example, a server-side function might query PostgreSQL using an appropriate database client or ORM.
The browser does not need direct access to your database credentials.
Keep Secrets on the Server
Never expose private credentials in client-side code.
Bad:
"use client";
const databasePassword = "secret-password";Never do this.
Server-only secrets should remain on the server.
Use environment variables for sensitive configuration:
DATABASE_URL
API_SECRET
PRIVATE_KEYThen keep your .env files out of Git.
.env
.env.localLoading UI
Data may take time to arrive.
The App Router supports loading.tsx.
For example:
app/
└── dashboard/
├── page.tsx
└── loading.tsxA simple loading component:
export default function Loading() {
return (
<div>
Loading dashboard...
</div>
);
}This allows you to provide loading UI while route content is being prepared.
The current Next.js learning course includes loading states and streaming as part of its App Router curriculum.
Error Handling
You can create:
error.tsxinside a route segment to provide error UI.
Example:
"use client";
export default function ErrorPage({
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Something went wrong.</h2>
<button onClick={() => reset()}>
Try again
</button>
</div>
);
}Error boundaries help prevent an error in one part of the application from destroying the entire user experience.
Not Found Pages
You can create:
not-found.tsxfor not-found UI.
Example:
import Link from "next/link";
export default function NotFound() {
return (
<main>
<h1>Page not found</h1>
<Link href="/">
Return home
</Link>
</main>
);
}For resource-specific routes, you can also trigger a not-found response when the requested resource doesn't exist.
Metadata and SEO
Next.js provides metadata APIs for pages.
For example:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Developer Resources",
description:
"Learn software development and cloud technologies."
};Metadata can help define:
- page title
- description
- social sharing information
- other document metadata
The current Next.js learning course includes metadata as a dedicated App Router topic.
Dynamic Metadata
For pages where metadata depends on the route, metadata can be generated dynamically.
For example, a blog page might use:
/blog/[slug]and generate a title based on the requested article.
This is useful for:
- blog posts
- product pages
- job pages
- documentation
- profiles
Search and Pagination
Next.js can work with URL search parameters.
For example:
/jobs?query=react&page=2The URL contains the search state.
This can be useful because:
- users can share the URL
- browser navigation works naturally
- pages can be bookmarked
- server-side rendering can use the parameters
The official Next.js App Router course includes search and pagination using URL search parameters.
Forms and Server Actions
Modern Next.js applications can use server-side mechanisms for mutations.
For example:
Create Post
↓
Submit Form
↓
Server-side Mutation
↓
Database
↓
Refresh / Revalidate UIThe current Next.js learning course includes data mutations using Server Actions and cache revalidation.
When building production forms, also consider:
- validation
- authorization
- CSRF-related protections where applicable
- rate limiting
- error handling
- user feedback
Authentication
Authentication determines who the user is.
Authorization determines what the user can access.
A typical application might have:
Login
↓
Authentication
↓
Session
↓
Protected Route
↓
Authorization
↓
ResourceNext.js itself provides the application framework, while authentication solutions can be added depending on your requirements.
The current Next.js learning material demonstrates authentication for protected dashboard routes.
Middleware and Proxy Concepts
Modern Next.js applications can use request-level logic for concerns such as:
- redirects
- authentication checks
- request handling
- routing decisions
However, don't put every piece of application logic into request middleware or proxy behavior.
Keep business logic in appropriate server-side modules.
The exact APIs and conventions can change between Next.js releases, so consult the current Next.js documentation when implementing these features.
Styling Next.js Applications
Next.js supports multiple styling approaches.
Common choices include:
- CSS Modules
- global CSS
- Tailwind CSS
- CSS-in-JS solutions
- component libraries
The right choice depends on the project.
For a team project, consistency matters more than choosing the trendiest styling technology.
Images and Fonts
Next.js provides built-in components and optimizations for common assets.
The official learning course includes optimization of fonts and images as part of its App Router curriculum.
For images, you can use:
import Image from "next/image";
export default function Profile() {
return (
<Image
src="/profile.jpg"
alt="Profile"
width={400}
height={400}
/>
);
}Always provide meaningful alternative text where appropriate.
A Practical Next.js Architecture
A medium-sized application might look like:
app/
├── layout.tsx
├── page.tsx
├── globals.css
│
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ ├── loading.tsx
│ ├── error.tsx
│ └── settings/
│ └── page.tsx
│
├── jobs/
│ ├── page.tsx
│ └── [id]/
│ └── page.tsx
│
├── api/
│ └── ...
│
├── components/
│ └── ...
│
└── lib/
└── ...The exact organization can vary.
The important thing is to maintain clear boundaries between:
- routes
- reusable components
- data access
- business logic
- configuration
Next.js Rendering Mental Model
A simplified model is:
Modern Next.js has several rendering and caching behaviors, so production applications should use the current documentation for version-specific details.
Next.js vs React
| React | Next.js |
|---|---|
| UI library | React framework |
| Components | Components + application features |
| Routing requires additional solution | Built-in routing conventions |
| Data fetching architecture is flexible | Framework provides conventions |
| Rendering choices are broader | Framework integrates server/client rendering |
| You assemble more pieces | Many pieces are integrated |
React is still the foundation.
Next.js builds an application framework around React.
Next.js vs Traditional React SPA
A traditional React SPA may look like:
Browser
↓
JavaScript Bundle
↓
React
↓
APIA Next.js application can use server and client components:
Browser
↓
Next.js
├── Server Components
├── Data
└── Client ComponentsThis gives developers more options for deciding where work should happen.
Common Next.js Mistakes
1. Making every component a Client Component
Don't add:
"use client";unless client-side capabilities are actually required.
2. Fetching everything in the browser
Some data can be fetched on the server.
Choose the location based on the application's requirements.
3. Exposing secrets
Never put private credentials into client-side code.
4. Ignoring loading states
Slow network requests need useful UI feedback.
5. Ignoring error handling
Real applications fail.
Provide useful error states.
6. Building giant components
Don't put an entire dashboard into one page.tsx.
Break reusable UI into components.
7. Mixing business logic everywhere
Keep data access and business logic organized.
8. Ignoring accessibility
Buttons, forms, links, images, headings, and navigation should remain accessible.
Practical Project: Developer Jobs Dashboard
Let's design a small Next.js application.
Requirements
The application should provide:
- job listings
- search
- pagination
- job details
- authentication
- saved jobs
- dashboard
- responsive UI
Possible structure:
app/
├── page.tsx
├── jobs/
│ ├── page.tsx
│ └── [id]/
│ └── page.tsx
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ └── saved/
│ └── page.tsx
└── login/
└── page.tsxProject Architecture
This project could demonstrate:
Next.js
React
TypeScript
Routing
Server Components
Client Components
Database
Authentication
Search
Pagination
Responsive DesignThat makes it a strong portfolio project.
A Simple Next.js Page
export default function HomePage() {
return (
<main>
<h1>Developer Jobs</h1>
<p>
Find software development opportunities.
</p>
</main>
);
}Simple is good.
Start with a working application before adding complexity.
Dynamic Job Page
File:
app/jobs/[id]/page.tsxExample:
export default async function JobPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return (
<main>
<h1>Job ID: {id}</h1>
</main>
);
}Now:
/jobs/123can represent job 123.
Learning Path for Next.js
If you're learning Next.js, follow this order:
React Fundamentals
↓
Next.js Project Setup
↓
App Router
↓
Pages
↓
Layouts
↓
Dynamic Routes
↓
Link Navigation
↓
Server Components
↓
Client Components
↓
Data Fetching
↓
Loading & Errors
↓
Search & Pagination
↓
Authentication
↓
Metadata
↓
DeploymentThe official Next.js learning course follows a similar progression from application setup through routing, data fetching, rendering, streaming, search, mutations, authentication, accessibility, and metadata.
Next.js Developer Skills Checklist
Before calling yourself comfortable with Next.js, try to understand:
- App Router
-
page.tsx -
layout.tsx - Dynamic routes
- Route groups
-
Link - Server Components
- Client Components
- Data fetching
- Loading states
- Error handling
- Not-found pages
- Metadata
- Forms
- Authentication
- Search parameters
- Pagination
- Image optimization
- Deployment
- Environment variables
Interview Questions
1. What is Next.js?
Next.js is a React framework for building full-stack web applications.
2. What is the App Router?
The App Router is Next.js's newer routing architecture based around the app directory and modern React features.
3. What does page.tsx do?
It defines the UI for a route.
4. What does layout.tsx do?
It defines UI that can be shared across routes within a layout hierarchy.
5. What is a dynamic route?
A route containing a dynamic segment such as:
app/products/[id]/page.tsx6. What is a Server Component?
A component rendered using Next.js's server-side component model, which can perform server-side work without requiring that component to become a Client Component.
7. What is a Client Component?
A component marked with:
"use client";when it needs client-side capabilities such as state, event handlers, or browser APIs.
8. When should you use a Client Component?
When the component needs browser-side interaction or APIs that aren't available in a Server Component.
9. Why use Link?
It provides Next.js-aware internal navigation and can take advantage of its navigation optimizations.
10. How do you create a dynamic route?
Use a dynamic folder segment such as:
[id]11. Why are layouts useful?
They allow shared UI and structure to persist across multiple routes.
12. Can Next.js connect to a database?
Yes. Server-side application code can communicate with databases, while credentials should remain server-side.
FAQ
Is Next.js only for frontend development?
No. Next.js can support full-stack web applications with server-side functionality and data access.
Do I need React before learning Next.js?
Yes, a basic understanding of React is strongly recommended. The official Next.js documentation lists familiarity with HTML, CSS, JavaScript, and React as prerequisite knowledge.
Should I learn the Pages Router first?
For modern Next.js development, learning the App Router is the more relevant starting point. The Pages Router is still supported, but the current documentation emphasizes the App Router for newer React capabilities.
Is every Next.js component a Server Component?
In the App Router, components are Server Components by default unless you opt into client behavior.
When should I use "use client"?
Use it when a component needs client-side capabilities such as interactive state, event handlers, or browser APIs.
Can I use TypeScript with Next.js?
Yes. Next.js supports TypeScript and can automatically configure the necessary packages and configuration when a project uses TypeScript.
Can Next.js build APIs?
Next.js can support server-side application functionality and route handlers, allowing applications to implement backend behavior alongside their UI.
Final Takeaway
Next.js becomes much easier to understand when you stop treating it as a collection of unrelated features.
Think about the application structure:
Next.js
│
├── Routing
│ ├── page.tsx
│ ├── layout.tsx
│ └── Dynamic Routes
│
├── Rendering
│ ├── Server Components
│ └── Client Components
│
├── Data
│ ├── Fetching
│ ├── Mutations
│ └── Database
│
├── User Experience
│ ├── Loading
│ ├── Errors
│ └── Navigation
│
└── Production
├── Metadata
├── Security
└── DeploymentThe most important concepts to learn first are:
App Router → Pages → Layouts → Dynamic Routes → Server Components → Client Components → Data Fetching → Loading/Error States → Authentication → Deployment.
Once these concepts make sense, Next.js stops feeling like a complicated React framework and starts becoming a practical tool for building complete web applications.
The official Next.js documentation and current App Router course are good references for continuing beyond these fundamentals.







Comments (0)
Be the first to share your thoughts.