Mastering Next.js App Router: Best Practices for Modern Web Apps
May 1, 2025

Mastering Next.js App Router: Best Practices for Modern Web Apps
Next.js 13+ introduced the App Router, a file-system based routing system that encourages server components, nested layouts, and a clearer separation between server and client code. The App Router helps build scalable, high-performance React apps when used with Next.js server and edge features
File-based routing
Create routes under the app/
directory. Files and folders map directly to routes
app/
page.js # /
about/
page.js # /about
blog/
page.js # /blog
[slug]/
page.js # /blog/:slug
Use colocated files (e.g., loading.js, error.js, page.js, layout.js) to control behavior for a route segment
Layouts
Layouts provide persistent UI across nested routes (navigation, footers, sidebars). Place a layout.js (or .jsx/.ts/.tsx) at a route segment to wrap its children
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Navbar />
{children}
<Footer />
</body>
</html>
);
}
Keep layouts small and composable so they can be reused across multiple routes
Loading & error UI
Place loading.js to show skeletons or spinners while server rendering/fetching. Use error.js to handle rendering errors for the segment
Example
// loading.js
export default function Loading() {
return <div className="loader">Loading…</div>;
}
// error.js
export default function Error({ error }) {
return <div className="error">Something went wrong: {error.message}</div>;
}
Metadata API
Use the metadata export (or generateMetadata) to configure SEO per route
export const metadata = {
title: 'Home | MySite',
description: 'Welcome to my site',
};
This gives you per-route control of titles, descriptions, Open Graph, and other head tags
Server and client components
By default, components in the App Router are server components. Add "use client" at the top of a file for client-side interactivity
// ToggleButton.jsx
"use client";
import { useState } from 'react';
export default function ToggleButton() {
const [on, setOn] = useState(false);
return (
<button onClick={() => setOn((s) => !s)}>
{on ? 'On' : 'Off'}
</button>
);
}
Prefer server components for rendering and data fetching when possible, and only opt into client components for UI that requires browser APIs or stateful interactivity
Best practices
Keep layouts modular and focused — compose small layouts rather than one large global layout
Separate server and client responsibilities. Fetch data in server components and keep UI logic in client components
Use loading.js and error.js to provide clear feedback during fetches and failures
Leverage the Metadata API for SEO and social sharing metadata at the route level
Co-locate CSS/modules and small components with the route that uses them for easier maintenance
Wrap-up
The App Router provides a clean architecture for scalable Next.js apps. Favor server components for performance, use nested layouts for structure, and keep client components minimal and focused to achieve a fast, maintainable codebase