Design Converter
Education
Developer Advocate
Last updated on Jun 3, 2024
Last updated on Apr 30, 2024
Next.js has rapidly become a go-to framework for React developers seeking to streamline the process of building web applications.
Before we dive into the specifics of the Next.js app and pages, let's take a moment to understand what Next.js is, its history, key features, and how it sets itself apart from other React frameworks.
Next.js was created by Vercel (formerly known as Zeit) and released in October 2016. The framework was developed to address some of the common pain points in React development, particularly around configuration and routing. Next.js aimed to provide a zero-configuration, single-command toolchain for React apps with server-side rendering (SSR) capabilities out of the box.
The purpose of Next.js is to enable developers to build server-rendered React applications with ease, as well as static websites, through static site generation (SSG). It focuses on performance, developer experience, and providing a set of conventions for building scalable applications.
Next.js comes packed with a variety of features that make it a powerful and flexible framework for modern web development:
Server-Side Rendering (SSR): Next.js allows pages to be rendered on the server, which can improve initial page load times and is beneficial for SEO.
Static Site Generation (SSG): With Next.js, you can pre-render pages at build time, which is great for static websites with content that doesn’t change often.
File-Based Routing: The framework uses the file system in the pages directory for routing, making route management straightforward and intuitive.
API Routes: Next.js enables you to create API endpoints as part of your Next.js app, allowing for a unified front-end and back-end development experience.
Built-In CSS and Sass Support: It offers built-in support for CSS and Sass, which can be imported directly into your components.
Image Optimization: Next.js provides an Image component that automatically optimizes images for better performance.
TypeScript Support: The framework has built-in TypeScript support, making it easier to use TypeScript for type checking and other advanced features.
Fast Refresh: Next.js includes a fast refresh feature that gives you instant feedback on edits made to your React components.
Server Component: Next.js utilizes server components that render on the server and stream to the client, significantly improving page loading times by migrating non-interactive parts of a component from a Client Component to a Server Component.
While there are several React frameworks available, Next.js distinguishes itself in a few key ways:
Convention Over Configuration: Next.js favors convention over configuration, meaning that it provides a set of defaults and standards that help reduce the time spent on setting up and configuring your project.
Hybrid Rendering: Next.js supports both SSR and SSG, as well as client-side rendering, giving developers the flexibility to choose the best rendering method for each page.
Zero Setup: It requires minimal setup to get started, thanks to its sensible defaults. This is in contrast to other frameworks that might require more configuration.
Optimized for Production: Next.js is designed with production in mind, offering features like automatic code splitting and server-side rendering, which can lead to better performance and user experience.
A Next.js app is a comprehensive solution for building both server-rendered and statically generated web applications using React. It encompasses the entire structure and functionality necessary to deploy a modern web application, from the user interface to API endpoints.
The introduction of the new app router enhances route organization and page creation, seamlessly integrating with the existing Pages directory to offer a more flexible routing mechanism. Let’s break down what constitutes a Next.js app and its core components.
The structure of a Next.js app is designed to streamline the development process with a focus on convention over configuration. Here's what you'll typically find in the app directory:
The ‘pages' Directory: This is where the magic of file-based routing happens. Each React component inside this directory corresponds to a route in your application.
The ‘public' Directory: Static assets like images, fonts, and other files that are not part of the React source code are placed here.
The ‘components' Directory: Although not required by Next.js, it's a common practice to have a directory for reusable React components.
Configuration Files: Files like next.config.js allow you to customize various aspects of Next.js, while .env files are used for environment variables.
A Next.js app comes with several key characteristics that enhance its capabilities:
Server-Side Rendering (SSR): Pages can be rendered on the server, which is beneficial for SEO and performance, as it allows the content to be indexed by search engines and reduces the time to first contentful paint.
Static Site Generation (SSG): Next.js can pre-render pages at build time, which is ideal for pages that do not require real-time data.
API Routes: You can create API endpoints within a Next.js app, allowing for seamless integration of front-end and back-end logic.
Built-In Routing System: The framework provides a built-in routing system based on the file system, eliminating the need for external routing libraries.
Example of a Basic Next.js App Structure
1// pages/index.js 2export default function Home() { 3 return <div>Welcome to my Next.js app!</div>; 4} 5 6// pages/api/hello.js 7export default function handler(req, res) { 8 res.status(200).json({ message: 'Hello from the API!' }); 9} 10 11// next.config.js 12module.exports = { 13 // Custom Next.js configurations 14};
In the example above, we have a simple Next.js app with a home page and an API route. The pages/index.js file represents the homepage of the app, and pages/api/hello.js defines an API endpoint that returns a JSON response.
Next.js pages are the building blocks of a Next.js app, representing the individual views or routes that users can navigate to within the application.
Each page is a React component that gets associated with a route based on its file name and location within the ‘pages' directory. Let's explore the role of Next.js pages and how they contribute to the app's functionality.
The ‘pages' directory is a special folder within a Next.js app that uses a file-based routing system. This system automatically generates routes that correspond to the file names of the React components inside the directory.
For example, a file named about.js in the ‘pages' directory would automatically be served at the /about route.
Next.js simplifies the routing process by eliminating the need for a separate routing configuration. Instead, it relies on the structure of the ' directory to determine the routes of the app. Here's how it works:
Top-Level Files: Each file in the ‘pages' directory corresponds to a route at the same path as the file name.
Nested Folders: Files inside nested folders within the ‘pages' directory represent subpaths in the route. For example, pages/blog/first-post.js translates to the /blog/first-post route.
Dynamic Routes: Files with square brackets, like [id].js, are used to create dynamic routes that can match multiple paths.
Next.js supports various types of pages, each serving a different purpose:
Static Pages: These are pages that do not require fetching data and can be pre-rendered at build time using static site generation (SSG).
Dynamic Pages: Pages that include dynamic content, often fetched from an external API or database, and may use server-side rendering (SSR) to render the content on the server.
API Pages: Special pages that reside in the pages/api directory and are treated as API endpoints rather than traditional web pages.
Next.js also defines a few special pages that have specific roles within the app:
_app.js: This file allows you to override the default App component, enabling you to add global styles or layout components that persist across all pages.
_document.js: Used to augment the HTML <Document>
structure, this file is where you can include things like custom fonts or meta tags that apply to the entire app.
_error.js: A custom error page that you can create to handle errors within your app.
Example of a Static Next.js Page
1// pages/about.js 2export default function About() { 3 return <div>About us page content here.</div>; 4}
In the example above, we have a static page that will be served at the /about route. This page does not require any data fetching and can be pre-rendered using static site generation.
Example of a Dynamic Next.js Page with Data Fetching
1// pages/posts/[id].js 2import { useRouter } from 'next/router'; 3 4export default function Post({ postData }) { 5 const router = useRouter(); 6 const { id } = router.query; 7 8 return ( 9 <div> 10 <h1>{postData.title}</h1> 11 <p>{postData.content}</p> 12 </div> 13 ); 14} 15 16export async function getServerSideProps(context) { 17 const { id } = context.params; 18 const res = await fetch(`https://example.com/posts/${id}`); 19 const postData = await res.json(); 20 21 return { props: { postData } }; 22}
In this dynamic page example, data is fetched on the server for each request using getServerSideProps. The page corresponds to the /posts/:id route, where :id is a dynamic segment that matches any specific post ID.
When developing with Next.js, it’s important to understand the distinction between the overarching app and the individual pages that comprise it. Both are integral to the functionality of a Next.js project, but they serve different purposes and have unique responsibilities.
The app router boasts additional features beyond basic routing, enhancing the app's overall capabilities. Furthermore, the app router introduces a significant evolution in routing within the Next.js framework, offering developers greater control and functionality.
Let’s compare the Next.js app as a whole with its constituent pages to clarify their roles and how they work together.
The Next.js app is the entire project, encompassing all the pages, components, and functionality. It includes the global settings, styles, and configurations that apply to the entire application.
The pages, on the other hand, are the individual units within the app that represent specific routes and views.
Next.js App: The container for the entire project, including global configurations, styles, and any server-side logic.
Next.js Pages: The components within the app that correspond to specific routes, each responsible for rendering the UI for that route.
Pages are a subset of the Next.js app's structure. They reside within the ‘pages' directory and are automatically associated with routes based on their file names. The app, however, includes much more than just the pages:
App Directory: Contains the ‘pages' directory, but also includes other directories and files that define the app's behavior, such as the ‘components' directory, ‘public' directory for static assets, and configuration files like next.config.js.
Pages Directory: Specifically for the React components that define the views for each route in the app.
App-level settings affect the entire application and are typically set in files like _app.js and next.config.js. Page-level settings are specific to individual pages and can include page-specific data fetching methods, styles, and SEO metadata.
App-Level Settings: Global CSS, custom <App>
component, custom <Document>
component, and overall project configurations.
Page-Level Settings: Page-specific logic, styles, getStaticProps/getServerSideProps for data fetching, and <Head>
tags for SEO.
Routing in a Next.js app is handled by the app router, which is built into the framework and uses the file system-based routing mechanism provided by the pages directory. Individual pages are mapped to routes based on their file names and directory structure.
The app router's programmability significantly benefits complex routing scenarios, enabling it to handle intricate routing needs like nested routes or dynamic routing based on external data.
App Router: Manages the navigation between pages and can include custom routing logic in _app.js.
Pages Router: Automatically generated based on the file structure within the pages directory.
Pages in a Next.js app can be rendered using server-side rendering (SSR) or static site generation (SSG), depending on the data requirements and the desired performance characteristics.
Server-Side Rendering (SSR): Pages that require fresh data for each request or need to be personalized for each user are good candidates for SSR.
Static Site Generation (SSG): Pages that can be pre-rendered at build time with data that doesn't change often are ideal for SSG.
Example of App-Level Configuration in Next.js
1// pages/_app.js 2import '../styles/globals.css'; 3 4export default function MyApp({ Component, pageProps }) { 5 return <Component {...pageProps} />; 6}
In this example, the _app.js file is used to import global styles that will apply to all pages in the Next.js app.
Example of Page-Level Data Fetching in Next.js
1// pages/posts.js 2export async function getStaticProps() { 3 const res = await fetch('https://example.com/posts'); 4 const posts = await res.json(); 5 6 return { props: { posts } }; 7} 8 9export default function Posts({ posts }) { 10 return ( 11 <div> 12 <h1>Blog Posts</h1> 13 {posts.map((post) => ( 14 <article key={post.id}> 15 <h2>{post.title}</h2> 16 <p>{post.excerpt}</p> 17 </article> 18 ))} 19 </div> 20 ); 21}
In this page-level example, getStaticProps is used to fetch data at build time for the /posts route, making it a static page.
In the world of Next.js, developers often need to decide when to focus on the app level and when to concentrate on individual pages. The decision is typically driven by the specific requirements of the feature or component being implemented. Let's explore some common use cases for both app-level and page-level development in Next.js.
Certain aspects of a Next.js project are best handled at the app level, where changes can have a global impact. Here are some scenarios where app-level focus is appropriate:
Global Styles: When you want to apply CSS styles universally across all pages, you would include them in the _app.js file.
Custom App Component (_app.js): To implement global functionality such as layout components, page transitions, or to inject additional props into every page.
Custom Document Component (_document.js): For customizing the HTML document structure, such as adding language attributes, or including external scripts that should load with every page.
Conversely, there are times when the focus should be on individual pages, particularly when dealing with page-specific concerns. Here are some examples:
Page-Specific Logic: When a feature or functionality is unique to a single page, such as form handling or page-specific event listeners.
Page-Specific Styles: If you need styles only relevant to a single page, you can include them within that page's component file to avoid polluting the global style scope.
Dynamic Routing with Page Parameters: When creating pages that rely on dynamic data, such as a blog post page that fetches content based on a URL parameter.
Example of Global Layout in Next.js
1// pages/_app.js 2import Layout from '../components/Layout'; 3import '../styles/globals.css'; 4 5export default function MyApp({ Component, pageProps }) { 6 return ( 7 <Layout> 8 <Component {...pageProps} /> 9 </Layout> 10 ); 11}
In the example above, a global Layout component is used in _app.js to wrap all pages, ensuring a consistent layout across the app.
Example of Page-Specific Data Fetching in Next.js
1// pages/products/[id].js 2export async function getServerSideProps({ params }) { 3 const res = await fetch(`https://example.com/products/${params.id}`); 4 const product = await res.json(); 5 6 return { props: { product } }; 7} 8 9export default function Product({ product }) { 10 return ( 11 <div> 12 <h1>{product.name}</h1> 13 <p>{product.description}</p> 14 {/* ... */} 15 </div> 16 ); 17}
In this page-level example, getServerSideProps fetches data for a specific product based on the dynamic [id] route parameter.
Throughout this exploration of Next.js, we've uncovered the distinctions and synergies between a Next.js app and its individual pages. The app provides the overarching framework and global settings, while pages serve as the unique content and functionality for each route.
Developers can craft efficient, optimized, and scalable web applications by understanding when to leverage app-level configurations and when to focus on page-specific details.
Remember to utilize the app router and pages router effectively, embrace the simplicity of the pages directory, and take advantage of the robust features that Next.js provides.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.