Next.js - An introduction
A quick introduction to Next.js, a React framework for building server-side rendered and static web applications.
Introduction
Next.js is a React framework for building server-side rendered and static web applications that has gained widespread adoption among developers due to its advanced features and ease of use.
Its features include hybrid rendering, dynamic routing and image optimization, among others. Let’s take a look at some of these features, particularly the new ones introduced in the latest 13 release.
What is Next.js?
Next.js was created by Vercel, a company that provides hosting and deployment services for web applications, and was first released in 2016 as an open-source project.
As a React framework, it provides a set of tools and conventions that make it easier to build React applications, such as a file-based routing system and data fetching methods. It also provides tools and configurations for bundling and compiling the application, using the Next.js Compiler written in Rust using SWC.
Image from Next.js documentation
Why use Next.js?
As previously mentioned, Next.js is a React framework, meaning that it is built on top of React and offers additional structure, features and optimizations. You can use React to build your UI and incrementally adopt Next.js features to solve common application requirements, which in most cases will be a better choice than building your own solutions or using third-party libraries.
There are several reasons why you should consider using Next.js:
- Performance - Next.js offers better performance with server-rendered pages.
- SEO - Next.js enables pre-rendering, which results in a set of static HTML pages that can be indexed by search engines.
- The benefits of a server - Next.js provides benefits similar to having a server in place, such as caching, routing, API routes, etc.
- Easy deployment - Next.js is well-suited for static sites and integrates easily with CI/CD tools pipelines.
I will now take a look at some of the features that make Next.js a great choice.
Features
Routing
Starting from version 13, the routing system is built on React Server Components and, as in previous versions, is based on the file system. This means that the file system is used to define the routes of the application, and that the routes are automatically generated from the file system structure.
The core of the routing system is the app
folder, at the root of the project.
Inside this folder, you can create any number of subfolders, and each of them will be mapped to a route. For example, if you create a dashboard
folder inside the app
folder, you will be able to access the dashboard page at the /dashboard
route.
You can have nested routes by creating subfolders inside the dashboard
folder, and you can also use dynamic routes by creating a folder with the name of the route prefixed with [
and suffixed with ]
. For example, if you create a folder named users
inside the dashboard
folder, you will be able to access the /dashboard/users
route, and if you create a folder named [id]
inside the users
folder, you will be able to access the /dashboard/users/:id
route.
Next.js provides a set of special files that can be used to define specific behaviors for the routes:
page.js
- the public UI of the routelayout.js
- the shared layout for the route and its childrenloading.js
- wraps the page in the React Suspense componenterror.js
- wraps the page in the ErrorBoundary componentnot-found.js
- the UI for the 404 page
Rendering
Next.js provides Server and Clients Components, meaning that the application can be rendered on the server or on the client, depending on what the developer wants.
There are four types of rendering:
- Client-side Rendering - the component is rendered on the client
- Server-side Rendering - the component is generated on the server for each request
- Static Rendering - the HTML is generated at build time, cached and served to the client, and reused for each request
- Dynamic Rendering - both server and client components are rendered on the server, and the client components are hydrated on the client
Data Fetching
Next.js has extended the fetch() API and uses async/await
with React Server Components.
This means you can fetch data inside components, as in these examples taken from the Next.js blog:
// app/page.js
async function getData() {
const res = await fetch('https://api.example.com/...');
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
return res.json();
}
// This is an async Server Component
export default async function Page() {
const data = await getData();
return <main>{/* ... */}</main>;
}
And you can also set and configure the caching behavior:
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });
Data can be fetched inside layout components as well, and the data is shared with the children components. You can use the loading and errors components to handle the request status on the UI.
Image Optimization
Next.js provides a built-in image optimization feature that allows you to optimize images for different devices and screen sizes, and to serve them in the most efficient way possible, improving the Core Web Vitals metrics.
With the Image
component, you simply have to provide the local path to the image, and Next.js will automatically optimize it for you. You don’t need to provide width
and height
attributes for local images, as Next.js will automatically calculate them for you.
import Image from 'next/image'
import profilePic from '../public/profile.jpg'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of me"
/>
<p>Welcome to my homepage!</p>
</>
)
}
export default Home;
The loader function generates the URLs of the optimized image, and the Image
component automatically generates the srcset
attribute for the img
tag, like in this example:
<img
src="/_next/image?url=%2Fprofile.jpg&w=1080&q=75"
srcset="/_next/image?url=%2Fprofile.jpg&w=1080&q=75 1x,
/_next/image?url=%2Fprofile.jpg&w=1080&q=75&dpr=2 2x"
alt="Picture of me"
/>
Middleware
Next.js provides a middleware system that allows you to add custom logic to the request/response cycle.
For example, you can add headers to the response:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
return NextResponse.next({
headers: {
'x-custom-header': 'hello world',
},
})
}
Conclusion
Next.js is a powerful framework that allows you to build modern web applications and a series of built-in features that make the development process easier and faster, SEO-friendly, and with great performances.
I wanted to give you a quick overview of the main features of Next.js, and why I think it’s a great choice over other JavaScript frameworks for your next project, but there are many other features that I didn’t cover, so if you want to learn more, I suggest you to check out the official documentation and the Next.js blog.
I hope you enjoyed this article, and if you have any questions or feedback, feel free to reach out to me on Twitter!