Explaining Next.js in Details: A Step-by-Step Guide for Beginners
What is Next.js?
Next.js is a popular open-source React front-end development web framework that enables functionality such as server-side rendering (SSR) and generating static websites for React-based web applications. It was originally created by Zeit (now Vercel) in 2016 and has since grown into a comprehensive framework with robust features catering to modern web development needs.
Installation and Setup
To get started, you need to have Node.js installed on your machine. Open your terminal or command prompt and run the following command to create a new Next.js project:
npx create-next-app@latest my-next-app
This command will scaffold a new Next.js project named my-next-app
with all necessary dependencies pre-installed. Navigate to your project directory using:
cd my-next-app
You can then start the development server by executing:
npm run dev
Or if you're using Yarn:
yarn dev
By default, this will start a local development server at http://localhost:3000
. Now, you're ready to start building your application!
Project Structure
A newly generated Next.js project comes with its own predefined structure, making it easy for beginners to understand and get started.
pages/: This is the most important folder in any Next.js project. Every file inside
/pages/
becomes a routable component. For instance:pages/index.js
corresponds to the root URL (/
).pages/about.js
corresponds to/about
.pages/projects/id.js
would correspond to dynamic routes like/projects/123
.
public/: This folder contains all the static files, such as images, favicons, etc., accessible directly via the web.
styles/: Here you can store CSS files and any custom Sass/SCSS files if you prefer styling with preprocessors.
components/: Though not automatically created, many developers keep their custom React components in this folder.
next.config.js (optional): Allows customization of the Next.js configuration, useful when integrating third-party services or setting up API endpoints and rewrites.
Server-Side Rendering (SSR)
In traditional client-side rendered applications built with frameworks like React, the entire interface is initially rendered on the client's browser once JavaScript loads. This means search engines can face difficulties indexing these pages because the content may not be immediately available. Also, users have to wait until JavaScript is loaded to see the full interface, affecting performance and user experience.
Next.js addresses this issue through Server-Side Rendering (SSR). It allows you to render each page on the server, converting your React components into plain HTML that search engines can crawl easily. SSR improves perceived load times since browsers no longer need to wait for Javascript execution before displaying initial content.
Here’s how to implement SSR in a Next.js page:
// pages/posts/[id].js
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export default function Post({ post }) {
const router = useRouter();
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
}
export async function getServerSideProps(context) {
// Fetch data from external API
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${context.params.id}`);
const post = await res.json();
// Pass data to the page via props
return { props: { post } };
}
In this example, getServerSideProps
fetches data from an external API every time a request is made to the route (/posts/[id]
). The fetched data is passed as props to the Post
component, which is then rendered on the server.
Static Site Generation (SSG)
Another powerful feature provided by Next.js is Static Site Generation (SSG), where pages are pre-rendered at build time into static HTML files. Once generated, these static files are served on the frontend without a need for the server to render them again for every request.
Static generation has numerous advantages including improved performance, faster load times, better SEO due to static HTML being immediately accessible by crawlers, and reduced hosting costs.
Example of SSG in Next.js:
// pages/posts/[id].js
export default function Post({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
}
export async function getStaticPaths() {
// Usually you would fetch this from an API or database
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
const post = await res.json();
// Pass post data to the page via props
return { props: { post } };
}
In the above code:
getStaticPaths()
defines a list of paths based on the data retrieved and informs Next.js about which paths should be pre-generated at build time.getStaticProps()
fetches the details of a specific post (based on its ID) and passes it as props to thePost
component during the build process.
Client-Side Rendering (CSR)
Not all applications demand data fetching on the server; sometimes, retrieving data asynchronously on the client works just fine. For instance, user-specific data that changes frequently is best fetched on the client side.
Client-side rendering in Next.js is achieved by creating a React component inside the /pages/
folder without any asynchronous data fetching functions.
Here’s an example:
// pages/contact.js
import React from 'react';
const ContactPage = () => {
return (
<div>
<h1>Contact us</h1>
<form>
<input type="text" name="name" placeholder="Your Name" />
<input type="email" name="email" placeholder="Your Email" />
<textarea name="message" placeholder="Your Message"></textarea>
<button type="submit">Send</button>
</form>
</div>
);
};
export default ContactPage;
API Routes
Next.js allows defining API routes within the /pages/api/
folder, enabling you to create backend functionalities with serverless functions on the fly. This makes it easy to build full-stack applications within the same framework.
Here’s a simple example:
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' });
}
With this route defined, you can make requests to it (http://localhost:3000/api/hello
) and receive JSON responses, effectively creating a quick backend using Node.js.
File-system Based Routing
One of the core philosophies of Next.js is simplicity and developer happiness. The framework automatically sets up routes based on the file names inside the /pages/
folder, eliminating the need for configuring routing manually as one might with React Router or Vue Router.
For example:
pages/index.js
results in the home route (/
).pages/about.js
generates an about route (/about
).
Even nested folders work seamlessly:
pages/blog/post-one.js
creates a blog post route like/blog/post-one
.
Styling Options
Next.js supports various styling methodologies out-of-the-box including CSS Modules, styled-jsx, Tailwind CSS, and SCSS/SASS.
CSS Modules are scoped CSS, meaning styles applied to a particular component do not affect those outside unless they share the same style classes.
Styled-jsx provides scoped CSS support but is inlined within JSX elements. It utilizes a BEM-like syntax under the hood to ensure unique class names per component.
Tailwind CSS leverages utility-first approach that allows rapid application development by applying utility classes directly within JSX rather than writing new CSS classes.
Here’s an example using CSS Modules:
// pages/about.module.css
.container {
padding: 1rem;
text-align: center;
}
.title {
font-size: 24px;
color: #333;
}
.description {
font-size: 16px;
color: gray;
}
// pages/about.js
import styles from './about.module.css';
export default function About() {
return (
<div className={styles.container}>
<h1 className={styles.title}>About Us</h1>
<p className={styles.description}>We are a team passionate about technology and innovation.</p>
</div>
);
}
This approach keeps your project organized by separating styles based on components.
Deployment
Deploying a Next.js app couldn't be easier with tools like Vercel. Vercel is a cloud platform that supports deployments for various types of projects, including those built with Next.js, thanks to seamless integration.
Just push your project code to a repository managed by Vercel, and it will build and deploy your application automatically.
Alternatively, you can build your project locally using:
npm run build
And then start the production server with:
npm start
Deploying on platforms like DigitalOcean, Heroku, AWS, or Azure also involves creating the build and running the production version of your app.
Custom App and Document
Next.js abstracts away much of the configuration needed for rendering React pages, but there are scenarios where developers might need additional customization. The _app.js
and _document.js
files inside the /pages/
folder serve these purposes.
_app.js: Acts as a custom root component that wraps the individual pages. It's typically used for global providers, shared UI components that must appear on all pages, or for customizing page loading behavior.
_document.js: Customizes the
<html>
and<body>
elements sent to the client. It’s primarily useful for adding custom HTML tags like global scripts or customizing the<head>
section, such as setting custom metadata or linking external resources like Google Fonts or analytics trackers.
Conclusion
By simplifying complex functionalities like server-side rendering, static site generation, and routing management, Next.js empowers developers to build high-performance, SEO-friendly, and feature-rich web applications quickly. Its ecosystem, combined with first-class support from Vercel, makes it an excellent choice whether you're building a small website or a large-scale web application.
With the foundation laid down here, you should feel equipped to explore more advanced features and best practices in the world of Next.js. Happy coding!