GSD

What is Next.js?

Posted by Maab Saleem on October 5, 2023

There’s plenty to consider when building a React application from scratch. You must bundle your app using a module bundler. You must split your code to optimize performance. You may also need to use server-side rendering and static pre-rendering for better SEO. 

Next.js is a React framework that can solve all these problems, and more. It requires zero configuration, automatically compiles and bundles code, and renders your app production-ready from the very start. A simple npm run dev gets a server up and running on your localhost.  

In this post, we will explore Next.js in more detail. We’ll talk about its architecture, types of applications you can build with it, share some code snippets, and explain why it’s the framework-of-choice for web development.   

What is Next.js?

Next.js is an open-source, flexible framework that simplifies the building of fast, user-friendly, and  SEO websites. It provides developers with all the building blocks they need to create a fully functioning, highly dynamic, and fast-loading website.

Whether you want to implement a hybrid data fetching and rendering approach, add API routes to your application, connect to a database, or integrate with a third-party application, Next.js enables you to do it all using a few lines of code.

Next.js logo next to a small plant

Here are some other cool features that Next.js provides out of the box:

  • An easy-to-use page-based routing system with support for dynamic routes 
  • Automatic code splitting which makes your website load much faster
  • Support for server-side rendering and static generation
  • Ability to perform route transitions on the client-side
  • Dedicated support for CSS and Sass

What can you build with Next.js?

You can virtually build any kind of website or digital product using Next.js. Here are a few examples:

  • Dynamic, user-friendly websites: Using features like dynamic routes, client-side navigation, and server-side rendering, you can build a truly dynamic, intuitive website.
  • Minimum viable product (MVP): Getting started with Next.js is as easy as running two commands. This helps you quickly build MVPs for different use-cases. 
    • Run npx create-next-app@latest to create a new application.
    • Run npm run dev to start the app server on localhost:3000.

You will be able to view your website by opening http://localhost:3000 on the browser. Edit the pages/index.js file and see your website change on the browser.

  • Web applications: Next.js lets you build performant web applications for the cloud. Whether you are building a streaming platform (see https://www.hulu.com/), a real estate website (see https://www.realtor.com/), a food ordering application (see https://www.doordash.com/), or a magazine (see https://www.vice.com/en), Next.js is the way to go.
  • Static websites: Using the next export command, you can easily transform your Next.js application into static HTML, which can then be run without a Node.js server. Moreover, you can create or edit static pages after you have built your website. This feature is known as Incremental Static Regeneration (ISR). 

ISR allows you to use static generation on a per-page basis, meaning you don’t have to regenerate the entire website. You get to enjoy the advantages of static while scaling to millions of pages. 

  • SaaS tools: The ease of development, maintainability, and integration makes Next.js a top choice for Saas tools. 
  • Big e-commerce websites: Next.js enables developers to meet the high scalability, performance, and rendering demands of big e-commerce websites, which can have millions of users. 
  • Client-side rendered websites/single page websites: A single page application (SPA) constantly rewrites the page dynamically to serve new content to the user. It doesn’t reload the page. An SPA requires fast transitions, high performance, and an intuitive user experience—all of which are easily achievable with Next.js.

banner-cta-next-blue.webp

How does Next.js work?

Next.js enables developers to use multiple data fetching techniques in the same project. It allows them to render some or all of the content on the server side before sending it to the browser. It does several things under the hood to optimize code in development and production environments. 

Developer environment optimizations

In a development setup, it optimizes for developers by providing features like ESLint integration and Fast Refresh.  It uses a Rust-based compiler which is 17 times faster than Babel, another famous compiler for JavaScript.

Its Speedy Web Compiler (SWC) component can automatically compile, minify, and bundle code. 

Built-in support for code splitting ensures that only the required code is loaded for an entry point, which significantly improves the speed of a website.

Production environment optimizations

When in production, Next.js optimizes for the end users. As you build your application, it transforms your code into production-ready files that are fine-tuned for maximum performance. It also supports three forms of rendering: server-side rendering, static site generation, and client-side rendering. 

Developers have the luxury to choose different forms of rendering for different pages, depending on the use case. By using a hybrid rendering approach, they can deliver truly dynamic and intuitive user experiences. 

Why use Next.js?

Next.js is the go-to framework for website development because it’s great for user experience, allows developers to build versatile React apps, and has a rich developer community. Here are some other reasons why you should choose Next.js for your next web app:

  • It’s one of the most feature-rich React frameworks: Built-in image and font optimization, automatic language detection, automatic prefetching, typescript support, file-system routing, fast refresh, and dedicated CSS support are only some of Next’s several features.
  • Faster time to market: Several built-in features and ready-to-use components, like dynamic routes, edge API routes, extensive MDX support, and preview mode,  enable you to build applications faster and decrease your time to market.
  • Monitor website performance with built-in analytics: Next.js Analytics calculates key metrics by collecting web vitals from the devices of your visitors. It generates an experience score based on several factors, like cumulative layout shift, first input delay, and largest contentful paint, etc. Analytics enables you to stay up-to-date with your website’s performance at all times.

undefined

  • Its SEO game is really strong: Next.js has several features and components dedicated to improving the SEO performance of a website. For example, next/amp can be used to enable AMP support,  the Link component can be used for client-side routing to improve on-page SEO, and the reportWebVitals function can be used to collect and monitor your core web vitals. Developers can usually optimize their websites for crawling, indexing, and ranking using a few lines of code/configuration.
  • It’s powering some of the biggest websites on the internet: GitHub, Twitch, Docker, Netflix, Hulu, Coinbase, and Uber all use Next.js to build their products.

Next.js and TypeScript

Next.js offers TypeScript support out of the box. There is no need to perform any manual configurations. This makes it easy for developers to write TypeScript code inside a React application. Creating a TypeScript project is as easy as running the following command: 

npx create-next-app@latest --ts 

If you have an existing project, you can enable TypeScript support by following these steps:

  1. Create an empty file named tsconfig.json in the root directory. Next.js will automatically fill this file with the default values.
  2. Then run npm run dev. Next.js should prompt you to execute the required command to install TypeScript. For example, you may get:
# Please install TypeScript, @types/react, and @types/node by running:
#
# yarn add --dev typescript @types/react @types/node 
  1. Execute the command.

That’s it! You are now ready to convert your .js files to .tsx and write strongly-typed TypeScript code!

Next.js and UX

User experience plays a crucial role in the success of an online business. A website with bad usability leads to high bounce rates and abandoned carts. Fortunately, you can use Next.js to build expansive, customized user experiences.

Unlike other frameworks which limit a developer’s ability to tweak code, Next.js gives developers full control over customization. It’s packed with different dynamic routing and scripting features which allow developers to tweak any and all parts of their applications.

Client-side routing

Using the Link component, you can implement client-side navigation. E.g., the following code can be used to navigate back to the homepage.

import Link from 'next/link';
export default function MyFunc() {
  return (
    <>
      <h1>Hello</h1>
      <h2>
        <Link href="/">
          <a>Go back to homepage</a>
        </Link>
      </h2>
    </>
  );
}

In a production environment, whenever Next.js detects the Link component, it automatically prefetches the content of the linked page in the background. This decreases the load time of the destination page when the user clicks the link.

Third-party JavaScript

You can also add third-party scripts to a Next.js page to introduce custom functionality to your application. Using the next/script component, you can perform optimized fetching and execution of third-party scripts. See the following code as an example:

import Script from 'next/script';

export default function MyFunc() {
  return (
    <>
      <Head>
        <title>Hello</title>
      </Head>
      <Script
        src="https://platform.twitter.com/widgets.js"
        strategy="lazyOnload"
        onLoad={() =>
          console.log(`script loaded correctly. `)
        }
      />
    </>
  );
}

Add component-level CSS

Next.js supports CSS modules, which can locally scope CSS by automatically defining a distinctive class name. This allows you to use the same class name across different files, without worrying about conflicts. 

Let’s consider an example:

First create a new file named components/Button.module.css  with the following CSS:

.error {
  color: white;
  background-color: red;
}

Then you can import and use the module in a JS file like this:

import styles from './Button.module.css'
export function Button() {
  return (
    <button
      type="button"
      className={styles.error}
    >
      Destroy
    </button>
  )
}

(Code snippets courtesy of official Next.js documentation: https://nextjs.org/docs/basic-features/built-in-css-support

Shared and per-page layouts

You can choose between a single layout for your entire application or per-page layouts. If you are using multiple layouts, the getLayout function can help you get the component for a layout.

import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

export default function Page() {
  return {
    /** add something here */
  }
}

Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}

(Code snippets courtesy of official Next.js documentation: https://nextjs.org/docs/basic-features/layouts

Faster load times using server-side rendering

Using server-side rendering, some of the HTML of a page gets rendered on the server before being sent to the browser. That decreases the time needed to display the first page on the client side, thus enhancing the user experience.

Using the getServerSideProps  function, you can implement server-side rendering for any page. For example:

// The server will call this function
export async function getServerSideProps({context}) {
 
  // Get the data from the API
  const data = await fetch(`MY_API`)

  
  return { props: { data } }
}

function Page({ data }) {
  // This will display the content to the user
  return(
    <div>{data}</div>
  )
}

export default Page

Next.js and SEO

Unlike other platforms, Next.js doesn’t require developers to write a lot of code or do several configurational tweaks to improve SEO. It packs several features that can optimize your website for search engines with little effort. Let’s look at some of them:

Easily add a robots.txt file

Since Next.js supports static file serving, we can create a robots.txt  file in the public folder of the root directory. For example, the following file will tell bots not to crawl /internal.

# Block all crawlers for /internal
User-agent: *
Disallow: /internal

# Allow all crawlers
User-agent: *
Allow: /

Generate dynamic sitemaps

Using the getServerSideProps  function, you can dynamically generate an XML sitemap. You can also manually create a sitemap.xml  file inside the public directory.

   <xml version="1.0" encoding="UTF-8">
   <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
     <url>
       <loc>http://www.sample.com/firstpage</loc>
       <lastmod>2022-07-01</lastmod>
     </url>
   </urlset>
   </xml>

Add metadata to pages

The Head component can be used to add metadata to pages.

import Head from 'next/head'; 
export default function MyFunc() {
  return (
    <>
      <Head>
        <title>Hello</title>
      </Head>
      <h1>Next app</h1>
    </>
  );
}

Robots and Googlebot tags

Using the robots tag, you can assist search engines and bots in indexing your website. For example, the following tag will tell search engines to not index a page, and also not follow any links on it.

<meta name="robots" content="noindex,nofollow" />

You can also use the googlebot tag to issue special instructions to Google.

<meta name="googlebot" content="noindex,nofollow" />

Monitor core web vitals with Analytics

The Analytics dashboard lets you measure your website’s performance using core web vitals, the main metrics that gauge a user’s experience while visiting a website. 

You can also send the aggregated data to a custom service or display it in your application logs. For example, use the following function to log the web vitals in real-time:

export function reportWebVitals(metric) {
  console.log(metric);
}

Next.js & e-commerce

Next.js Commerce is a comprehensive toolkit for developing performant e-commerce websites. Commerce integrates seamlessly with many e-commerce platforms, including Shopify, Vendure, Swell, BigCommerce, and OrderCloud. There are several demo sites built by the Next.js team which showcase how Commerce and these platforms work together:

You can set up a Commerce store with a few clicks directly from the official Next.js website. All you have to do is sign in to your GitHub account, create a Git repository, choose the platforms to integrate with, and click Deploy. 

Commerce comes packed with several features that make it a great choice for building large e-commerce stores:

  • It’s fast out of the box. Being “performant by default” was a design goal while building Commerce.
  • It’s SEO-ready and supports internationalization.
  • It supports dark mode.
  • There is extensive support for UI customization and theming.
  • Turn features like custom checkout, wishlist, search, and cart on/off by tweaking a configuration file. Disabling a feature will also remove all the source code related to it.

banner-cta-next-blue.webp

Next.js & how developers use it

Next.js has developed a strong reputation among the developer community owing to its several programmer-friendly features. Here are some of them:

Fast refresh

A live editing experience where developers can get instant feedback on edits made to components. If you are running v9.4 or newer, fast refresh will be enabled by default, making most edits visible within a second. Here are a few more neat things about fast refresh:

  1. When you remove syntax errors and re-save your file, the errors go away on their own. No need to reload the app.
  2. In case a runtime error occurs, a contextual overlay will appear. Once you fix the error, the overlay will go away without requiring an app reload.
  3. If you modify a file that only has React components, Next.js will only update code for that file and render your component again.

API routes

You can build your API routes with middleware, GraphQL, REST, and CORS. All you need to define an API route is to make a function default and pass the req (instance of http.IncomingMessage) and res (instance of http.ServerResponse) parameters to it. For example:

export default function handler(req, res) {
  if (req.method === 'POST') {
    // Process a POST request
  } else {
    // other HTTP methods are handled here
  }
}

Lazy load external libraries and components using dynamic import

Another excellent way to decrease the initial loading time is by lazy loading external libraries and React components. For the former, you can use import(), and for the latter, you can use next/dynamic. In the following example, the header component won’t be a part of the initially loaded JavaScript bundle, and will be rendered only when the Suspense boundary gets resolved. 

import dynamic from 'next/dynamic'
import { Suspense } from 'react'

const DynamicHeader = dynamic(() => import('../components/header'), {
  suspense: true,
})

export default function myFunc() {
  return (
    <Suspense fallback={`Loading...`}>
      <DynamicHeader />
    </Suspense>
  )
}

Overriding the default app component

Next.js uses the app component to initialize pages by default. Developers can override app and implement a custom app. This can have several benefits:   

  1. Keeps state during page navigation
  2. Adds global CSS to your application
  3. Uses the componentDidCatch module to implement customized error handling
  4. Injects any needed data to pages upon initialization 

Work with environment variables

Built-in support for environment variables allows you to use env.local to load environment variables and expose them to the browser by adding a NEXT_PUBLIC_ prefix to them. A sample env.local file can be:

…and then to access them in code:

export async function getStaticProps() {
  const database = await database.connect({
    host: process.env.DATABASE_HOST,
    username: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASS,
  })
  // ...
}

Are there any downsides to using Next.js?

It’s hard to think of too many cons of Next.js, but here are a couple:

  • Fewer number of stable plugins: Compared to other frameworks, like Gatsby, Next.js has a fewer number of plugins. 
  • No built-in way to perform state management: Next.js doesn’t have a dedicated component for state management. It relies on the built-in state management of React, which is notoriously error-prone.

Closing thoughts

Next.js is slowly becoming the staple of modern web architectures. It allows developers to fast-track the development of scalable, efficient, and user-friendly web applications. This post was meant to share all the things you need to get started with Next.js. To learn more, you can go through the extensive documentation available on the official website. 

For more articles on using Next.js, read:

Or, check out our Next.js starter projects, Next.js headless CMS, and blog engine.

Make sure you receive the freshest Next.JS tutorials and Butter product updates.
Maab Saleem

Maab is an experienced software engineer who specializes in explaining technical topics to a wider audience.

ButterCMS is the #1 rated Headless CMS

G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award

Don’t miss a single post

Get our latest articles, stay updated!