DEV Community

Vishnu Sivan
Vishnu Sivan

Posted on • Updated on

Build your web apps using Next.js

Using modern technologies, the world is finding ways to stretch and enable new possibilities in online experiences. Users require experiences which are faster and easier in the case of online services. 

React is a JavaScript library created by Meta for building user interfaces. It has become one of the most popular frontend libraries today. However, it requires some additional packages to work on full potential. To overcome this issue, Vercel created Next.js which is built on top of React framework which enables the building of production ready application. It supports authentication, routing, bundle optimization etc. without any configuration or third-party packages.

Getting Started

Table of contents

  • What is Next.js
  • Evolution of Next.js
  • Features of Next.js
  • Next.js vs React.js
  • Create your first Next.js app
  • Next.js 13 updates
  • Handson with Next.js 13

What is Next.js

React is a JavaScript library that is used for building web applications on the client's browser. It has gained popularity as the most used library among developers. However, developers faced several difficulties with the client-side rendering strategy of react such as lack of authentication, security issues, extended page loading time etc. On the other hand, Next.js eludes these problems by allowing the website to be rendered on the server-side before being sent to the client.

Next.js is an open-source web development framework built on React's UI library created by Vercel. It is lightweight, server-rendered and flexible framework that includes several additional features such as server-side rendering and generation static websites.

Nowadays, most of the developers are moving towards Next.js to build static, fully interactive, superfast and SEO friendly sites and apps that are fast and easy to use. Next.js supports styling with CSS as well as precompiled Scss and Sass, CSS-in-JS and styled JSX. The main feature of Next.js includes its capability of server-side rendering to reduce the burden on web browsers which can be applied to any part of the application or the entire project.

Evolution of Next.js

Next.js was launched in 2016 and it only provided service-side rendered at that time. Later it started supporting both frontend and backend development using React and Javascript. It enables developers to create full-stack applications using a single language which avoids the complexity of developing applications using different languages and frameworks. Later, it started providing automatic routing, data fetching, and built-in SSR methods. It also supports multiple rendering methods.

Rendering Methods in NextJS

Next.js supports three types of rendering:

1. Service Side Rendering (SSR)

For each request, the content is generated on the server and then it's sent to the browser.
When user requests a page, Next.js calls a serverless function for returning backend data that is necessary to render the page. The data fetching is done in the getServerSideProps() method.

2. Pre-rendering (SSG)

It is also known as Static Site Generation (SSG), where the page is rendered before the application is deployed during the initial build. This feature was added in next.js3 as a part of the CI/CD build process.
Later, Next.js was updated with Js6 and the routes were automated for both SSG and SSR. In Next.js 9, automatic static optimization was introduced that determines if the page can be rendered as static. This unique feature was adopted by Nuxt and Gatsby.

3. Deferred Rendering (ISR)

It is also known as Incremental Static Regeneration (ISR) where the page is rendered when requested by the user. It was introduced to reduce the long build time. So, subsequent users will see the page either when the optional cache time expires or when a new build occurs. If the content is user-generated or generated on request, then ISR and SSR work best.

Features of Next.js

Server Side Rendering (SSR)

When the user requests a page, the content is generated on the server side and sent to the browser. The user can read the contents of the page without waiting for the contents to load, which makes faster page loading. It also provides indexable and crawlable website, which is essential for Search Engine Optimization (SEO).

SSR
Image credits Next.js tutorial with examples (educative.io)

Data Fetching

Next.js provides two kinds of pre-rendering services. SSR enables data fetching and rendering when requested. Static generation uses the data that is already available before the request is made or during build time. It is useful where data can be pre-rendered for SEO or is publicly cached.

Automatic code splitting

Instead of creating a single JavaScript consisting of all application codes, Next.js uses libraries and JavaScript to breaks it down codes into smaller parts and serves it as and when required. This makes page loading faster, as the browser doesn't have to download Javascript and CSS.

Hot Module Replacement (HMR)

Hot module Replacement (HMR) allows developers to see any changes they have made as live in the application during development. Unlike traditional "live reload" methods, it only reloads the modules that were modified. It preserves the state of the application which significantly reduces the amount of time required to see the changes in action.

Persistent Caching for Page Bundles

Next.js supports persistent caches for pages that are not changed. It allows users to load the pages quickly in their browsers as it stores the static contents in persistent caches.

Routing

Routing is one of the core features of Next.js. Next.js uses the file-based routing system and every folder and file created inside the pages folder is automatically converted to route in Next.js.
Next.js routing system is mainly divided into three - Index routing, nested routes, dynamic routes.

Index Routing

The index.js is automatically mapped as the deafult route (/) for the homepage. For instance, you can define pages/contact/index.js, which will automatically be mapped to the /contact page.
For the above page structure, next.js creates the URL structure as / for the pages/index.js, /contact/ for the pages/contact/index.js, and /contact/details for pages/contact/details.js respectively.

index routing

Nested Routes

Nested routes are created within a parent route. To create a nested route, create a parent route/folder within the pages folder and add folders or files to it.
For the above page structure, the details.js and index.js files are nested with the contact parent route.

nested routes

Dynamic Routes

To create a dynamic route, add a square bracket [id].js around the filename or the directory name.
The script above makes the [detials].js dynamic, which means the user page must be accessed with /user/arun/contact or /user/vishnu/contact.

dynamic routes

Absolute Imports

Absolute imports resolve the issue of long import components statements with relatively long directories.
Users don't need to import components as below,

import InputField from "../../../../../components/contact/forms/inputfield"
Enter fullscreen mode Exit fullscreen mode

Instead, they can import components as below,

import InputField from "components/contact/forms/inputfield";
Enter fullscreen mode Exit fullscreen mode

Linking Pages

Next.js provides the next/link for navigating between pages.
For instance, the project structure is as below,

linking pages
You can implement page navigation as below,

import Link from "next/link";

export default function Users({users}) {
  return (
    <div>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/contact">Contact</Link>
      <Link href="/users">Users</Link>
      <Link href="/users/admin">Admin</Link>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Next.js vs React.js

React and Next.js are the most popular JavaScript libraries used to build user interfaces (UI).
This section, we will be focused on the comparison between React.js and Next.js.

Pages and navigation

In React, react-router is used to provide page navigation by providing routes for each component. The react-router-dom library is installed and imported for each component for implementing routing in react. 
Next.js provides a file-based router by default to implement routing.

Server-side rendering vs Client-side rending

React uses Client-side rendering where the entire app is rendered on the screen by the browser. In React, only a basic HTML file with JavaScript is rendered and everything else is rendered by the browser. 

Next.js uses Server-side rendering where the HTML file is prepared by the server and then sent to the client-side to be displayed on the UI. 

As a result, the initial page loading in Next.js is much faster than React. Moreover, Next.js apps are more efficient for SEO because of Server-side rendering.

Data fetching

Next.js provides two types of pre-rendering - static generation and server-side rendering. Next.js uses getStaticProps, getServerSideProps function for pre-rendering. When the page is loaded on the client end, these functions are executed first and the code inside getStaticProps and getServerSideProps is not visible to the client.

In a React app with redux, actions are dispatched from the components by using the useEffect hook, reducers then update the state in the store. The useSelector hook is used to fetch the state of the component. 

In a Next.js app, the getStaticProps method is used to call the APIs and once the data is fetched, it is sent to the component via props. If the data is continuously changing, the getServerSideProps function is used.

Next.js Image optimization

The <img> tag is used for displaying images in web pages. However, Next.js provides a new API, next/image for image optimization. It offers better performance, asset flexibility, faster page loading, and visual stability.

react vs next

Create your first Next.js app

In this section, we will create a Next.js application. Creating a new Next.js project is an easy task with the help of create-next-app CLI.

Prerequisites

To create a Next.js application, ensure you have nodejs and npx or npm or yarn installed on your machine.

  • node.js v14 or higher [download]
  • npm v6 or higher

Create a sample app

Create a project folder and open the terminal on that folder. 
Execute the following command in the terminal to create a next.js app.

npx create-next-app
Enter fullscreen mode Exit fullscreen mode

create-next-app
create-next-app is a package like create-react-app, but for Next.js projects. It gives us a Next project with all its dependencies installed with addition to some dummy pages and styles.

Run the app

Execute the following commands to run the app.

cd <project-name>
npm run dev
Enter fullscreen mode Exit fullscreen mode

npm run dev

The Next.js app "development server" will start on port 3000 and you should see a page as below when you access http://localhost:3000. This is the starter template page which provides some helpful information about Next.js.

output

Project Structure

After creating a new Next.js project from a CLI, you'll notice the default folder structure of the project. It contains specific folders such as pages, public, and styles.
The default folder structure for a new Next.js project is as given below.

Project Structure

Next.js 13 updates

App directory 

Routing

Routing within the app directory is controlled by the folders inside it. The UI for a route is defined with a page.jsx file inside that folder. For instance, folder structure app/user/settings/page.jsx will render /user/settings route.
There are a few optional files that can be automatically wrapped with the react pages such as loading.jsx, error.jsx, layout.jsx, template.jsx.

  • loading.jsx file - An optional file that is displayed immediately when a component is first loaded or when navigating between the sibling routes. It can be created within any directory inside the app folder.
  • error.jsx file - An optional file that isolates the error to the smallest possible subsection of the app. The component will be replaced with it's contents whenever any error occurs inside the folder where this file is placed.
  • layout.jsx file - Used to define a UI that is shared across multiple places. A layout can render another layout or a page inside it.
  • template.jsx file - Similar to the layout.jsx file, a new instance of the component is mounted during navigation, but the state is not preserved. Layouts and templates allow us to take advantage of a concept known as partial rendering.

Mandatory root layout

There must be a file that defines the root layout at the top level of the app directory. This layout is applicable to all the routes in the app and it must define the and the <body> tags.

Head tag

A head.jsx file defines the contents of the <head> tag for that folder. It can only return certain limited tags like <title>, <meta>, <link>, and <script>.

Route groups

Every folder inside the app directory contributes to the URL path. All the files and folders inside of this folder are said to be a part of that route group.

Server components

By default, all of the components created inside of the app directory are React server components. However, we can include client side codes using the use client directive in the file.

Handson with Next.js 13

Let's experiment with some of the latest features of Next.js 13. We will be working on the sample project that we have created in the previous sections for this handson.
The page and layout file

  • Open the layout.jsx file and comment out the global.css file import.
  • Open the page.jsx file and replace the return statement as follows.
return <h1>Hello, Next.js!</h1>;
Enter fullscreen mode Exit fullscreen mode
  • Run the server to see the output.
npm run dev
Enter fullscreen mode Exit fullscreen mode

output2

  • Check how the layout file impacts the overall UI. Create a layout.module.css file in the same directory and add the following code to it.
.header {
    width: 96%;
    padding: 2%;
    background-color: blue;
    color: white;
    text-align: center;
    font-size: 1.5rem;
}
Enter fullscreen mode Exit fullscreen mode
  • Import the styles in the layout.jsx file and add it to a div inside the body tag.
// import './globals.css'
import styles from './layout.module.css'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      {/*
        <head /> will contain the components returned by the nearest parent
        head.jsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
      */}
      <head />
      <body>
        <div className={styles.header}>My First Next App</div>
        {children}
      </body>
    </html>
  )
}
Enter fullscreen mode Exit fullscreen mode

The output will be as below,

output3
Add a new folder in the app directory called info. 
Create a file named page.jsx inside it and add the following code to it.

export default function Page() {
  return (
    <div>
      <h3>This is a handson on next.js 13 features.</h3>
      <hr />
      <h4>
        Next.js 13.1 includes improvements to both the pages/ (stable) and app/
        (beta) directories:
      </h4>
      <ul>
        <li>
          app Directory (Beta) Improvements: Improved reliability and
          performance.
        </li>
        <li>
          Built-in Module Transpilation: Bringing next-transpile-modules
          capabilities into core.
        </li>
        <li>Edge Runtime (Stable): A light Node.js runtime for the Edge.</li>
        <li>
          Turbopack Updates: Support for Tailwind CSS, next/image, @next/font,
          and more.
        </li>
        <li>
          Middleware Improvements: Return responses and set request headers.
        </li>
        <li>
          SWC Import Resolution: For smaller JavaScript bundles when using
          barrel files.
        </li>
        <li>Memory usage improvements, new templates, and more!</li>
      </ul>
      <p>
        For more: <a href="https://nextjs.org/blog/next-13-1">Next.js 13.1</a>
      </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Navigate to the info route http://localhost:3000/info to see the output.

output4

Testing the loading file

Let's create loading.jsx file inside the info folder using the following code.

export default function Loading() {
    return <h1>Loading...</h1>
}
Enter fullscreen mode Exit fullscreen mode

Add a navigation link inside the info/pages.jsx file to navigate to the default (/) route.

<p>return to <Link href="/">main page</Link></p>
Enter fullscreen mode Exit fullscreen mode

The loading UI will appear for a second when user clicks on the main page link.

Testing the error file

Create an error.jsx file in the info folder and add the following code to it. This file will act as an error boundary in case any error occurs either inside this component or to any of its components in its subtree.

'use client';

import { useEffect } from 'react';

export default function Error({
  error,
  reset,
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error);
  }, [error]);

  return (
    <div>
      <div>ERROR</div>
      <p>Something went wrong!</p>
      <button onClick={() => reset()}>Reset error boundary</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Two props are passed to this component: the error prop provides more details about the error, and the reset function resets the error boundary.

Data fetching

Let's try to fetch random jokes from the Jokes API in the app.
Create a new folder called jokes within the app folder. 
Create a file called pages.jsx and add the following code to it.

async function getData() {
  const res = await fetch(
    "https://v2.jokeapi.dev/joke/Programming?type=single&amount=10"
  );
  return res.json();
}

export default async function Page() {
  const data = await getData();
  return (
    <div>
      <h2>Tell me a joke</h2>
      <hr />
      <ul>
        {data &&
          data?.jokes?.map((item, index) => {
            return <li>{item?.joke}</li>;
          })}
      </ul>
      {data.joke}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Navigate to the jokes route http://localhost:3000/jokes to see the output.

output5
Thanks for reading this article.
Thanks Gowri M Bhatt for reviewing the content.
If you enjoyed this article, please click on the heart button ♥ and share to help others find it!
The full source code for this tutorial can be found here,
GitHub - codemaker2015/next-app-demo: my first next app
The article is also available on Medium.
Here are some useful links,

Top comments (0)