In Quantum Metropolis, engineers design advanced transportation systems that can operate both on classic roads and on new quantum teleportation routes. Similarly, Next.js offers two parallel routing systems: the traditional Pages Router and the modern App Router. In this module, we will thoroughly analyze the differences between these two approaches and understand how to organize files and directories in our projects.
Next.js originally relied on a routing convention based on directories in the
pages/ folder. In Next.js 13, a new routing system based on the app/ folder was introduced. This evolution resembles the transition from classic transportation systems to quantum teleportation in Quantum Metropolis - the new technology is more advanced, but both still coexist.The Pages Router is the original routing system in Next.js. It is simple, well-documented, and still widely used. In this convention, every JavaScript or TypeScript file in the
pages/ directory automatically becomes a route in the application.1pages/
2βββ index.js # Route: /
3βββ about.js # Route: /about
4βββ contact.tsx # Route: /contact
5βββ products/
6β βββ index.js # Route: /products
7β βββ [id].js # Route: /products/:id (dynamic)
8βββ api/
9 βββ hello.js # API Endpoint: /api/helloIn this system:
[param]api/ directory is used for handling API endpointsThe App Router, introduced in Next.js 13 and refined in version 15, represents a new approach based on React Server Components. It is like transitioning from traditional vehicles to quantum teleportation - a fundamental change in how we think about web applications.
1app/
2βββ layout.tsx # Main layout (required)
3βββ page.tsx # Route: /
4βββ about/
5β βββ page.tsx # Route: /about
6βββ blog/
7β βββ page.tsx # Route: /blog
8β βββ layout.tsx # Layout specific to /blog and its sub-routes
9β βββ [slug]/
10β βββ page.tsx # Route: /blog/:slug (dynamic)
11βββ api/
12 βββ users/
13 βββ route.ts # API Endpoint: /api/usersIn the App Router:
page.tsx file renders the page component for a given routelayout.tsx file defines a shared layout for all pages in the directory and its subdirectories[param]route.ts filesThe App Router introduces "convention over configuration" with a series of special files that have specific roles. This is like specialized modules in Quantum Metropolis systems - each with a defined function in the overall architecture.
page.tsx: Renders the route's user interface and makes the path publicly accessible.
1// app/dashboard/page.tsx
2export default function DashboardPage() {
3 return (
4 <section>
5 <h1>Quantum Metropolis Control Panel</h1>
6 <p>Welcome to the command center!</p>
7 </section>
8 );
9}layout.tsx: Defines a shared interface for a segment and its children.
1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3 children,
4}: {
5 children: React.ReactNode;
6}) {
7 return (
8 <div className="dashboard-layout">
9 <nav className="dashboard-sidebar">
10 {/* Sidebar navigation */}
11 </nav>
12 <main className="dashboard-main">{children}</main>
13 </div>
14 );
15}route.ts: Creates an API endpoint using the new request handling API.
1// app/api/status/route.ts
2import { NextResponse } from 'next/server';
3
4export async function GET() {
5 return NextResponse.json({
6 status: 'online',
7 systemsOperational: 15,
8 time: new Date().toISOString()
9 });
10}
11
12export async function POST(request: Request) {
13 const data = await request.json();
14 // Processing data...
15 return NextResponse.json({ success: true });
16}loading.tsx: Creates a loading interface with React Suspense.
1// app/dashboard/loading.tsx
2export default function DashboardLoading() {
3 return (
4 <div className="dashboard-loading">
5 <div className="spinner"></div>
6 <p>Loading Metropolis system data...</p>
7 </div>
8 );
9}error.tsx: Creates an error handling interface with React Error Boundary.
1'use client'; // Error handling components must be client components
2
3import { useEffect } from 'react';
4
5export default function DashboardError({
6 error,
7 reset,
8}: {
9 error: Error;
10 reset: () => void;
11}) {
12 useEffect(() => {
13 // Log error to monitoring system
14 console.error(error);
15 }, [error]);
16
17 return (
18 <div className="error-container">
19 <h2>An error occurred in the Metropolis systems!</h2>
20 <p>{error.message}</p>
21 <button onClick={reset}>Try again</button>
22 </div>
23 );
24}not-found.tsx: Creates an interface for a not-found resource (404).
1// app/not-found.tsx
2export default function NotFound() {
3 return (
4 <div className="not-found">
5 <h2>Unknown Zone</h2>
6 <p>No Quantum Metropolis module was found with that identifier.</p>
7 <a href="/">Return to command center</a>
8 </div>
9 );
10}The App Router introduces several advanced organizational features that resemble the advanced transportation systems in Quantum Metropolis - they allow for more complex and flexible routes.
Route groups allow organizing files without affecting the URL structure. They are marked by enclosing the directory name in parentheses:
(group-name).1app/
2βββ (marketing)/ # Route group (does not affect URL path)
3β βββ about/
4β β βββ page.tsx # Route: /about
5β βββ contact/
6β βββ page.tsx # Route: /contact
7βββ (dashboard)/ # Another route group
8 βββ layout.tsx # Shared layout for dashboard routes
9 βββ page.tsx # Route: /
10 βββ stats/
11 βββ page.tsx # Route: /statsRoute groups are like districts in Quantum Metropolis - they help organize the city structure, but don't necessarily affect addresses.
Parallel routes allow simultaneous rendering of multiple pages in the same view, which is useful for complex layouts. They are marked by a slot name with the "@" sign:
@slot-name.1app/
2βββ layout.tsx # Main layout
3βββ page.tsx # Main page
4βββ dashboard/
5 βββ layout.tsx # Layout with multiple slots
6 β // layout.tsx defines slots {children, @stats, @notifications}
7 βββ page.tsx # Default content for the main slot
8 βββ @stats/
9 β βββ page.tsx # Content for the @stats slot
10 βββ @notifications/
11 βββ page.tsx # Content for the @notifications slot1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3 children,
4 stats,
5 notifications,
6}: {
7 children: React.ReactNode;
8 stats: React.ReactNode;
9 notifications: React.ReactNode;
10}) {
11 return (
12 <div className="dashboard-grid">
13 <main>{children}</main>
14 <aside className="stats-panel">{stats}</aside>
15 <section className="notifications-panel">{notifications}</section>
16 </div>
17 );
18}Parallel routes are like parallel dimensions in Quantum Metropolis - different realities accessible simultaneously.
These allow "intercepting" a route and displaying it differently, which is ideal for modals that preserve navigation context. They are marked by the segment name with the sign "(.)":
(.)name, (..)name or (...)name.1app/
2βββ layout.tsx
3βββ page.tsx # Route: /
4βββ dashboard/
5 βββ layout.tsx
6 βββ page.tsx # Route: /dashboard
7 βββ projects/
8 βββ page.tsx # Route: /dashboard/projects
9 βββ [id]/
10 β βββ page.tsx # Route: /dashboard/projects/:id
11 βββ (.)create/ # Intercepts /dashboard/projects/create
12 βββ page.tsx # Displayed as a modal over /dashboard/projectsIntercepting routes are like quantum shortcuts in Quantum Metropolis - they allow quick access to resources without changing context.
Besides the routing structure, Next.js 15 suggests specific ways of organizing code. This is like planning districts in Quantum Metropolis - proper organization increases efficiency and readability.
Components used in multiple places should be organized consistently. Here is the recommended structure:
1src/
2βββ app/ # Application with App Router
3β βββ layout.tsx
4β βββ page.tsx
5βββ components/ # Shared components
6β βββ ui/ # Basic UI components
7β β βββ Button.tsx
8β β βββ Card.tsx
9β βββ features/ # Feature-specific components
10β βββ dashboard/
11β βββ auth/
12βββ lib/ # Shared functions and classes
13β βββ api/
14β βββ utils/
15βββ hooks/ # Custom React hooks
16β βββ useAuth.ts
17β βββ useLocalStorage.ts
18βββ styles/ # Global styles
19 βββ globals.cssNext.js 15 and the App Router support a "co-location" approach, where files related to a specific route are placed close together. This is like micro-districts in Quantum Metropolis - everything you need is nearby.
1app/
2βββ dashboard/
3 βββ page.tsx
4 βββ loading.tsx # Loading for this route
5 βββ error.tsx # Error handling for this route
6 βββ layout.tsx # Layout for this route
7 βββ actions.ts # Server Actions for this route
8 βββ components/ # Components specific to this route
9 β βββ StatusCard.tsx
10 β βββ DashboardNav.tsx
11 βββ styles/ # Styles specific to this route
12 βββ dashboard.module.cssNow that we've explored both routing systems, let's compare them - just as Quantum Metropolis engineers might compare classic transport with quantum teleportation.
Pages Router:
App Router:
Pages Router:
App Router:
Pages Router:
App Router:
Pages Router:
App Router:
Choosing between App Router and Pages Router resembles choosing between quantum teleportation and traditional transport in Quantum Metropolis - it depends on specific needs.
If you have an existing project using Pages Router, you can gradually migrate to App Router. This is like modernizing districts in Quantum Metropolis - you don't have to rebuild everything at once.
Next.js 15 allows both systems to coexist. You can start using
app/ for new features while keeping existing pages in pages/.1.
2βββ app/ # New features using App Router
3β βββ new-feature/
4β β βββ page.tsx # /new-feature
5β βββ layout.tsx
6βββ pages/ # Existing pages using Pages Router
7 βββ index.js # /
8 βββ about.js # /aboutImportant notes about migration:
app/ take priority over routes in pages/pages/ to app/Regardless of the chosen routing system, it's worth following certain best practices:
Feature-oriented structure: Organize components and code around business features, not by technical types.
1src/
2βββ features/
3β βββ auth/
4β β βββ components/
5β β βββ hooks/
6β β βββ utils/
7β βββ dashboard/
8β βββ components/
9β βββ hooks/
10β βββ utils/Modular approach: Treat each feature as an isolated module with a clearly defined API.
Consistent naming conventions: Establish conventions and stick to them throughout the project.
Relative vs. absolute imports: Use import aliases (
@/) for better readability and easier file moving.Test co-location: Place tests close to the tested components.
1src/
2βββ components/
3β βββ Button.tsx
4β βββ Button.test.tsxThe directory and file structure in Next.js 15 is like the architecture of Quantum Metropolis - with proper planning, it can be both elegant and functional. The App Router introduces a more advanced but also more flexible application organization model, while the Pages Router offers a simpler and more direct approach.
The choice between them depends on the specific needs of the project, but for new projects, it is recommended to use the App Router to take advantage of the latest features and optimizations. Remember that good project organization is the key to easy maintenance and extensibility in the future.
In the next module, we will dive into the Next.js 15 component system, particularly the differences between Client Components and Server Components, which are a fundamental part of the App Router.