Next.js 15 introduces several advanced routing techniques that enhance the flexibility and efficiency of web application development. Below are some key routing features, along with examples and use cases for each.
App Router
The App Router is the foundation of routing in Next.js 15. It uses a file system based router where folders are used to define routes.
app/
page.js
about/
page.js
contact/
page.js
Code Example:
// app/page.js
export default function Home() {
return <h1>Welcome to my website!</h1>
}
// app/about/page.js
export default function About() {
return <h1>About Us</h1>
}
// app/contact/page.js
export default function Contact() {
return <h1>Contact Us</h1>
}
How to use: Create folders and files in the app
directory. Each page.js
file becomes a route.
When to use: Use this for all your Next.js 15 projects. It’s the default and recommended way to structure your application.
Dynamic Routing
Dynamic routing allows developers to create routes that are not predefined but instead depend on dynamic data. This is particularly useful for applications that need to display content based on user input or external data sources.
Code Example:
To create a dynamic route, you can use square brackets in the folder name. For instance, if you want to create a blog where each post is accessible via a unique ID, you would structure your folders like this:
/app
/blog
/[id]
page.js
In page.js
, you can access the dynamic segment using params
:
export default function BlogPost({ params }) {
return <h1>Blog Post ID: {params.id}</h1>;
}
Dynamic routing is ideal for content-heavy applications like blogs, e-commerce sites, or user profiles, where the content is generated based on unique identifiers.
Route Interception
Route interception allows developers to intercept navigation and modify the route behavior dynamically. This can be useful for implementing features like modals or confirmation dialogs before navigating away from a page.
Example
You can create a route interceptor by using a higher-order component or a custom hook that listens for route changes. For instance:
import { useRouter } from 'next/router';
const useRouteInterceptor = () => {
const router = useRouter();
useEffect(() => {
const handleRouteChange = (url) => {
if (!confirm('Do you really want to leave?')) {
router.events.emit('routeChangeError');
throw 'Route change aborted';
}
};
router.events.on('routeChangeStart', handleRouteChange);
return () => {
router.events.off('routeChangeStart', handleRouteChange);
};
}, []);
};
Use Case
This technique is particularly useful for applications where unsaved changes could be lost if a user navigates away, such as forms or editing interfaces.
Parallel Routes
Parallel routes allow multiple routes to be rendered simultaneously, which is useful for layouts that require displaying different components or views at the same time.
Example
To set up parallel routes, you can create a folder structure like this:
// app/layout.js
export default function Layout({ children, dashboard, analytics }) {
return (
<>
{children}
{dashboard}
{analytics}
</>
)
}
// app/@dashboard/page.js
export default function Dashboard() {
return <div>Dashboard Content</div>
}
// app/@analytics/page.js
export default function Analytics() {
return <div>Analytics Content</div>
}
How to use: Create folders starting with @
and use them as named slots in your layout.
When to use: When you need to show multiple independent components or pages in the same view, like a dashboard with different sections.
Intercepting Routes
Explanation: Intercepting routes allow you to load a different route than the current URL segment, useful for modal overlays.
Code Example:
// app/feed/page.js
export default function Feed() {
return <h1>Feed</h1>
}
// app/feed/(..)photo/[id]/page.js
export default function PhotoModal({ params }) {
return <div>Photo {params.id} Modal</div>
}
How to use: Use (..)
to go up one level, (...)
to go to the root, or (.)
to match the same level.
When to use: When you want to display content (like a modal) while keeping the user on the current page context.
Route Groups
Explanation: Route groups let you organize routes without affecting the URL structure.
Code Example:
// app/(marketing)/about/page.js
export default function About() {
return <h1>About Us</h1>
}
// app/(shop)/products/page.js
export default function Products() {
return <h1>Our Products</h1>
}
How to use: Create folders with parentheses (folderName)
to group routes.
When to use: When you want to organize your project files logically without impacting the URL structure.
Loading UI and Streaming
This feature allows you to show a loading state while the page content is being prepared.
Code Example:
// app/dashboard/loading.js
export default function Loading() {
return <div>Loading...</div>
}
// app/dashboard/page.js
import { Suspense } from 'react'
function SlowComponent() {
// Simulating a slow component
return <div>Slow Component Loaded</div>
}
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<div>Loading slow component...</div>}>
<SlowComponent />
</Suspense>
</div>
)
}
How to use: Create a loading.js
file in the same folder as your page.js
. Use Suspense
for component-level loading states.
When to use: When you have pages or components that might take some time to load and you want to provide a better user experience.
Catch-All Routes
Catch-all routes allow you to capture all routes that match a certain pattern, simplifying the handling of nested routes.
Example
To create a catch-all route, use three dots in square brackets:
/app
/docs
/[[...slug]]
page.js
In page.js
, you can handle all nested routes under /docs
:
export default function Docs({ params }) {
return <h1>Docs Path: {params.slug.join('/')}</h1>;
}
Use Case
Catch-all routes are particularly useful for documentation sites or any application where you want to handle a variable number of nested routes without explicitly defining each one. This flexibility can greatly reduce the complexity of your routing configuration.
Conclusion
Next.js 15 provides powerful routing capabilities that enhance the development experience for complex applications. By leveraging dynamic routing, route interception, parallel routes, catch-all routes, and route groups, developers can create more flexible and user-friendly web applications. Each technique serves specific use cases, allowing for better organization and management of routes in modern web development.