What Next.js Has to Offer React Developers

Next.js is sometimes confused with React. In the last few years, it's solidified itself as one of the leading frontend frameworks. In this article, Jeffery Morhous shows off what makes Next.js important to React developers, and teaches you how to build your own highly-performant blog.

Next.js is one of the hottest web frameworks of 2022. It supplements React applications with server-side rendering, static site generation, and more. Picking and choosing which parts of the site to generate on the server rather than on the client can speed up your site while maintaining usability.

Developers familiar with React will find getting started with Next to be not too big of a stretch, and migrating existing apps just as approachable.

Many companies are already using Next.js in production at scale, such as Netflix, Uber, Hulu, and more!

In this article, we'll explain what Next.js is and how it differs from React. You'll also learn what makes Next.js so great, see how to migrate from Create React App, and get hands-on experience with building your own blog with the framework.

Why Next.js?

React is an incredibly popular and powerful JavaScript library. However, using React to run production applications often requires some additional dependencies. Traditionally, it's been popular for developers to use Create React App to bootstrap their application, as it comes with a webpack, Babel, ESLint, and a few other dependencies. Middleware, Typescript support, and routing all ship with Next.js as zero-configuration development tools.

Next.js expands on React's capabilities, introducing a framework for creating apps that are rendered on the server. It contrasts with Create React App, which pushes the responsibility of rendering all pages to the browser.

Server-Side Rendering

Server-side rendering (SSR), is not a completely new concept. By doing a lot of the computational work a single time on the backend, pages are quickly loaded in the browser. Sending less JavaScript code to be executed on the browser shifts that responsibility to the server, which means it can benefit from doing something once and repeating it multiple times.

Static generation is similar; in many cases, content doesn’t change between application builds. Static content can be generated once and served to the client upon request in a system that resembles a cache. These pages can even be hosted on a CDN and delivered to the client even faster. Still, many pages on a React site will have pages with dynamic content, which can still be rendered on the server and delivered to the client.

Speed and Search Engine Optimization

Beyond elevating the user experience, another clear benefit of speeding up the rendering of a website is search engine optimization (SEO). Speed is so important to ranking well on search engines that it’s included in Google’s published description of what their indexers use to rank websites for performance, called Core Web Vitals.

Having a performant website and high Core Web Vitals scores does not guarantee a good ranking in search results, but a slow website will disqualify itself from ranking well. Search engine companies, Google in particular, want users to be happy with the results shown, and speed is a huge factor in that. Speeding up your React site by leveraging Next.js is a good way to secure a double win with happier users and better search rankings.

Incrementally Adopting Next.js from Create React App

If you're already running React in a production application at scale, you're probably not too excited about a major migration. Fortunately, Next.js is built in a way that it can be incrementally adopted into an application.

Migrating from Create React App introduces risk due to the scope of the change, but also requires development time that may be needed to continue work-in-progress.

Migration to Next.js from Create React App begins with removing react-scripts. This can be done by running the following in your project directory:

npm uninstall react-scripts

Next, install Next.js in your project directory by running the following:

npm install next

Then, update the scripts section of package.json. Replace the scripts section with this:

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start"
}

Next, you'll change how the public directory is used. Move all static assets, including images, into this directory.

The index.html file should be moved to the root directory. This should be changed to match Next.js standards, which involves extracting code from <head> into a new _document.js file.

Next.js comes with its own file-based routing, so if your project is using React Router, it can be removed as a dependency. Instead, you'll create a new pages directory. Move App.js to the pages directory and rename it index.js.

If your application uses React Router extensively, the maintainers of Next.js have written a more in-depth guide on migrating to Next.js' file-based routing.

The Next.js guide on migrating from Create React App goes more in depth on each of these topics and even discusses ejecting Create React App.

Creating a New Next.js Application

Next.js is easier to adopt in a new application, and some even consider it easier to use than Create React App due to the zero-config setup process.

You can find the code in this section on GitHub.

Basic Environment Setup

If you don't already have Node.js installed, you'll need to install it. On Mac, it's easiest to install it with Homebrew by running the following:

brew install node

If you haven't already, install the npm package called npx by running the following:

npm install -g npx

Bootstrap the Application

Finally, you can create a new React app with Next.js by running the following:

npx create-next-app@latest

Once that finishes, you can run your development server with one of the scripts. In the new project directory created by the wizard, run the following:

npm run dev

Visiting localhost:3000 in your browser should show you your new app!

Next.js Template Homepage

Using Next.js to Build a Static-Site Blog with Some React Parts

Without much effort, you can turn your newly created Next.js app into a well-designed blog.

File-Based Routing

Because Next.js uses file-based routing, the URL of a page is typically its relative file path from the pages directory. Inside your pages directory, make a new directory called blog. You can do this from the command line by running the following:

mkdir pages/blog

Inside the new directory, create a new file for a blog post, called pages/blog/i-learned-next.js.

Inside the new file, create a new React component with just an h1 tag that looks like this:

export default function ILearnedNextJS() {
  return <h1>I Learned Next.js</h1>;
}

Visiting localhost:3000/blog/i-learned-next takes you to your new page and demonstrates Next's zero-config file-based routing.

Blogging in Markdown

Next.js pre-renders every page by default, generating HTML and only the essential JavaScript. When pages are loaded, JavaScript "hydrates" the page, making it the interactive application one would expect. This results in faster load-times, leading to happier users and better SEO. The pre-rendering takes place as either static generation, for pages that don't change often, or server-side rendering, which is slower but allows for dynamic content.

To implement static generation in Next.js, simply use the getStaticProps method in a page. `getStaticProps instructs Next.js to resolve dependencies at build-time, fetching data before creating the HTML.

We can take advantage of this to fetch-blog content from markdown files, enabling a cleaner writing experience. Start by creating a new directory in the root of your project to store the files:

mkdir markdown

Inside this markdown folder, create a new file called i-learned-next.md. In this file, paste the following markdown:

---
title: 'I learned Next.js'
date: '2022-09-03'
---

I spent some time learning Next.js. The Honeybadger blog is a great
place for me to learn new programming things, and Jeff is my favorite
author there.

Next, install a package that will help us parse the header information from the markdown blog posts.

npm install gray-matter

Finally, we'll need to create a file that can parse the markdown. Start by creating a new lib directory:

mkdir lib

The Next.js website offers a wonderful example of a function that parses markdown metadata and returns a list of posts, as well as a few other functions. We'll copy that. In lib, create a file called posts.js and paste the following:

import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

const blogDirectory = path.join(process.cwd(), 'blog');

export function getSortedPostsData() {
  // Get file names under /posts
  const fileNames = fs.readdirSync(blogDirectory);
  const allPostsData = fileNames.map((fileName) => {
    // Remove ".md" from file name to get id
    const id = fileName.replace(/\.md$/, '');

    // Read markdown file as string
    const fullPath = path.join(blogDirectory, fileName);
    const fileContents = fs.readFileSync(fullPath, 'utf8');

    const matterResult = matter(fileContents);

    return {
      id,
      ...matterResult.data,
    };
  });
  // Sort posts by date
  return allPostsData.sort(({ date: a }, { date: b }) => {
    if (a < b) {
      return 1;
    } else if (a > b) {
      return -1;
    } else {
      return 0;
    }
  });
}


export function getAllPostIds() {
  const fileNames = fs.readdirSync(blogDirectory);

  return fileNames.map((fileName) => {
    return {
    params: {
        id: fileName.replace(/\.md$/, ''),
    },
    };
  });
}

export async function getPostData(id) {
  const fullPath = path.join(blogDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, 'utf8');

  // Use gray-matter to parse the post metadata section
  const matterResult = matter(fileContents);

  // Use remark to convert markdown into HTML string
  const processedContent = await remark()
    .use(html)
    .process(matterResult.content);
  const contentHtml = processedContent.toString();

  return {
    id,
    contentHtml,
    ...matterResult.data,
  };
}

At the top of page/index.js, paste the following:

import { getSortedPostsData } from '../lib/posts';

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData,
    },
  };
}

This calls the getSortedPostsData() function at build-time, generating an array of all the posts called allPostsData.

getPostData uses remark to display the actual text, so we'll need to install it:

npm install remark remark-html

Display a List of Blog Posts

Your index.js has everything needed to display the blog posts in the markdown directory. You'll simply pass allPostsData in as a prop to the Home component and display each post in a loop. Your Home component (inside index.js) should look like this:

export default function Home({ allPostsData }) {
  return (
    <div className={styles.container}>
      <Head>
        <title>Jeff's Blog</title>
      </Head>

      <main className={styles.main}>
        <h2 className={styles.title}>Blog</h2>
        <ul className={styles.description}>
          {allPostsData.map(({ id, date, title }) => (
            <li key={id}>
              <Link href={`/blog/${id}`}>
                <a>{title}</a>
              </Link>
            </li>
          ))}
        </ul>
      </main>
    </div>
  )
}

This code displays a "Blog" header and creates a dynamic list of blog posts with links to them.

Display a Blog Post

First, delete the previously created i-learned-next.js. In its place, create a file in the blog directory called [id].js. In this file, paste the following code:

import { getAllPostIds, getPostData } from '../../lib/posts';

export async function getStaticProps({ params }) {
  const postData = getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

export async function getStaticPaths() {
  const paths = getAllPostIds()
  return {
    paths,
    fallback: false
  }
}

export default function Post({ postData }) {
  return(
    <div>
      <h1>{postData.title}</h1>
      <br />
      <h2>{postData.id}</h2>
      <br />
      <h3>{postData.date}</h3>
      <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
    </div>
  )
}

This simply calls the methods in posts.js to fetch the id and post data for the blog post. It then renders the title, ID, and date. Next, it follows the metadata and displays the post content, translating markdown to HTML!

Conclusion

By now, you should have a functioning Next.js application that statically generates pages from blog posts written in markdown. Your existing React applications can benefit from the static-site generation or server-side rendering that makes Next.js such an incredible framework. If you're starting from scratch, the framework's zero-config setup makes it easy to start making a fully featured web application that picks and chooses what pages get rendered based on maximum utility for the user. If you followed along with creating your own blog, you can take what you've learned and develop it into your own production application!

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Jeffery Morhous

    Jeff is a Software Engineer working in healtcare technology using Ruby on Rails, React, and plenty more tools. He loves making things that make life more interesting and learning as much he can on the way. In his spare time, he loves to play guitar, hike, and tinker with cars.

    More articles by Jeffery Morhous
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like:

    “Everyone is in love with Honeybadger ... the UI is spot on.”
    Molly Struve, Sr. Site Reliability Engineer, Netflix
    Start free trial
    Are you using Sentry, Rollbar, Bugsnag, or Airbrake for your monitoring? Honeybadger includes error tracking with a whole suite of amazing monitoring tools — all for probably less than you're paying now. Discover why so many companies are switching to Honeybadger here.
    Start free trial
    Stop digging through chat logs to find the bug-fix someone mentioned last month. Honeybadger's built-in issue tracker keeps discussion central to each error, so that if it pops up again you'll be able to pick up right where you left off.
    Start free trial
    “Wow — Customers are blown away that I email them so quickly after an error.”
    Chris Patton, Founder of Punchpass.com
    Start free trial