Next.js - Taking React.js to a whole new level

Published on: Tue Oct 19 2021

Series

Content

Introduction

If you are using React.js, Next.js is the framework to be using today on your team. That is unless you have a very good reason to rolling your own solution.

In this analysis, we start by understanding the evolution of React.js, Next.js and how they come together.

Then, I go into the details about the pro and cons of the framework. Of course, nothing is perfect so take the good with the bad.

I personally think the pros outweigh the cons. With that said, every project is different which is why I included a few more sections to discuss some of the stand out or missing features.

Beyond that, we also analyze what using a framework, like Next.js, means for a growing team. As your team grows, communication tends to become the bottle neck. Then you start to consider issues like hiring and on-boarding, it becomes even more complicated. If the proper strategy is not in place to address these growing issues then it‘ll affects the productivity of the teams, existing and new.

Finally, we glimpse into the future of some exciting direction the team is taking. Also, we take a look at the current landscape and some of the competing frameworks and plaforms available in the market.

Understanding the need

Next.js was created to address various gaps in the existing solutions within the React ecosystem.

With the rise of React.js, one of the single page application (SPA) web framework, much of the website is rendered on the client side.

Single page applications serves to provide a seamless end-user experience on the website and web application.

It has shifted the way the site gets loaded, by providing everything that is needed to run the application upfront, then as the user interacts with the site, it gathers new data from the server as the user navigates through it.

Now constrast that with a traditional website where you’d need to reload each page for new content. Can you imagine going through a shopping cart experience where every click reloads the whole page ?

To further complicate the situation, add in different languages, currencies and managing content.

This makes SPA a great fit to address most of the issues related to having a dynamic website but with those trade-offs introduced other problems like SEO and customers using low end devices.

SEO

Everything up to this point sounds great. However, with this optimization comes a huge trade-off, which is SEO. Now that most of the interactions has been delegated to the client side, the site information is no longer available to the search engines. Many of the engines are designed to crawl and index the information of the sites.

So, that means the html content needs to be served on the server some how.

Server side rendering (SSR) as a solution

A common solution is to provide a server to perform “Server side rendering” (SSR) which is just a fancy way of saying the client side app is rendered as html on the server, and it gets served to the client who requested the page.

Prior to Next.js, if SEO was important to the business then this required many software teams to develop a SSR solution in order to achieve this. So, in a way many teams built their own internal framework.

There are pros and cons to that, over the long term, it becomes a “build versus buy a solution“ analysis. With the extra flexibility you get in the internal framework, you also take on some risk as the solution grows which requires upkeep and further maintenance (especially on a large team).

Additionally, Next.js provides many comprehensive features to build a modern a website or web application. This is why I believe Next.js is the leading React.js framework for any software teams building a particular type of website and web application today.

It makes it especially suitable for any content heavy, marketing, and ecommerce websites. However, with many of the other benefits the framework provides, it may still make sense to adopt it depending on goals of the team or the business.

In-depth analysis

My overall impression of Next.js from start to finish is solid. The setup from start to feature development was very streamlined.

You can almost treat the Next.js framework like a blackbox. Basically, you can just rely on the great documentation, and community available for anything related to the framework, even for any custom configurations.

Here are just some of the pros and cons that I have gathered from the framework:

Pros

  • Great Documentation
  • Open source code
  • No overhead with managing an internal framework
  • Zero configuration required unless you required custom configurations
  • Supports various techniques to serve content (SSG, SSR, CSR, ISR etc)
    • SSG - static site generation
    • SSR - server side rendering
    • CSR - client side rendering
    • ISR - incremental static re-generation
  • Superb development experience (DX) with internal CLI
    • npx create-next-app@latest to create a new project
  • Optimization techniques built into the framework (Image optmization, route code splitting etc)
  • Strong community adoption and support
    • Majority of the popular open source libraries have next.js in their examples
  • Platform agnostic (but very tailored towards Vercel platform)
  • Good SEO out of the box
  • Great research & development with strong engineering team with core contributors from open source community (webpack , swc )

Cons

  • Lack of support for react-router (yet ? maybe ?)
    • Does not look like there are any intention to support it in their roadmap anytime soon
  • Opinionated in their setup (build, development)
  • Optimization is strictly based on using their convention and internal libraries
  • Some gotchas (environment variables etc)
  • Issues with Typescript watch locally (likely due to the hot reload)
  • Pages are sometimes slow to load locally

Beyond just SEO

So, as I mentioned earlier Next.js solves various issues beyond just the SEO. The Next.js team really thought about the framework end-to-end and streamlined it. Especially if you are using their cloud platform, Vercel.

Below are just a few more details I noticed.

Optimiziation

This is achieved through Next.js’s filesystem routing where each page is automatically code splitted so the page only loads what is needed per page.

The setup would look something like this:

pages/
├── index.tsx
└── blog
    ├── [id].tsx
    └── index.tsx

This folder structure contains routes for / , /blog and /blog/:id

This comes with their convention for handling data fetching:

  • getStaticProps() (SSG / ISR)
  • getServerSideProps() (SSR)
  • getInitialProps() (CSR)

In addition, Next.js provides image optimization through the framework as well.

<Image
  alt="My image"
  placeholder="blur"
  blurDataURL={imageUrl}
  src={imageUrl}
  width={950}
  height={500}
/>

It is slightly an opinionated setup but many teams would appreciate all these capabilities if they need it. Otherwise, these are likely features they would need build themselves if the choose to build their own framework.

Various approaches of serving content

Next.js supports various ways to serve your content.

Methods:

  • Server side rendering (SSR)
  • Static site generation (SSG)
  • Incremental static regeneration (ISR)
  • Client side rendinerg (CSR)

They all have their trade-offs but fundamentally the approach chosen comes down to how frequently does your content change and the type to experience you’d like to provide.

Or said in another way, it depends how up-to-date your content need to be on your website. An election poll site has very different requirements than a blog.

An extra call out for ISR, which is in between SSG and SSR. essentially, it generates the page statically but re-generates the page based on an cache expiry time as new request comes in. This expiry time is configurable.

References:

Next.js - ISR

Lack of platform tooling

Next.js works seamlessly if you use their cloud platform, Vercel. However, if you choose to bootstrap your own infrastructure on something like AWS, it takes more work.

Which makes sense, my understanding is that Vercel is their core business. So, much of the tooling with infrastructure, CI/CD is to be handled by your own team if they choose to roll their own infrastructure.

Interestingly, Next.js also offers built-in convention for deploying api as functions through Vercel.

You define a function inside api/* and when you deploy it, this endpoint will be available on a serverless function with no extra work or configuration required.

If you were to set this up your self, it would take a lot of work just setup the infrastructure alone!

Lack of support for react-router

If you have been using React.js on your site for sometime then likely you are using react-router for the site’s routing solution.

Unfortunately, as of today, Next.js does not support this natively (yet). They have opted out to have their own router and link, next/router and next/link .

My guess is that as of now, with their file based routing, supporting react-router and the nested routes will be just too complicated. So, they decided to go with their own solution for now. Who knows ?

However, remaining hopefully, there is a dicusssion on an github issue #1632 which goes into this discussion.

There are comments that the teams have added that they do intend to support it in the longer term. It just does not seem like a priority at the moment though.

Gotchas

Environment Variables

One of the big gotchas with the framework was the way it handled environment variables. It seemed to be a common area of confusion. I had many team members ask about what is the deal with the configuration and how to safely expose variables.

The documentation is quite clear but you can get a little paranoid if you don’t understand how things work behind the scenes.

The convention used by Next.js for Environment Variables are as follows:

  • NEXT_PUBLIC_* - Is public (replaced at build time)
  • process.env.* - Is server and build only (run time - loaded via .env* )

Next.js also provides another way to “expose“ the config through the next.config.js (replaced at build time):

// next.config.js

module.exports = {
  env: {
    MY_PUBLIC_SECRET: process.env.MY_PUBLIC_SECRET
  }
};

Transpiling custom modules

Generally, when using webpack, best practice is to ignore node_modules/* as it is assumed we will use the distribution files provided by the package.

Sometimes you want to make some minor changes at build time to the different packages in your node_modules/* folder (ie changing imports).

If so, this can be achieved through the package next-transpile-modules.

Here is an example with @mui/material@5.x using styled-components :

// next.config.js

const withTM = require('next-transpile-modules')([
  '@mui/material',
  '@mui/system',
  '@mui/icons-material',
]);

module.exports = withTM({
  webpack: (config) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      '@mui/styled-engine': '@mui/styled-engine-sc',
    };
    return config;
  }
});

Growing the team

Knowledge base and information available

For a growing framework like Next.js, I believe it has already won as the go-to framework to build React.js sites and web applications.

The community growth is just tremendous. Many popular React.js based library has an example using Next.js for their library (styled-components, emotion, material-ui etc).

The information available on Next.js and the talented people working on the framework is ever growing. These include core-contributors from webpack, swc and many other.

I believe this makes it a great framework to adopt.

As with any growing teams, communication and knowledge sharing becomes more and more important. If the intention is many people are going to use this framework, the process should be in place to ensure individuals involved have enough context and details to perform their duties.

Next.js has solved many of these issues.

These may include and not limited to:

  • Documentation
  • Knowledge base & active community
  • Developer experience
  • Standardized release process and versioning strategy

Having these processes in place also improves team morale, and reduces friction when using the framework. It takes work to build and grow a framework.

Even more so to foster of a community, and provide on-going support. If this type of work isn’t contributing to the main value proposition of your business then I think its best to start delegating it. There is no need to re-invent the wheel.

Hiring

It becomes even more important when it comes to hiring, and on-boarding new engineers to the team.

Engineers want to work on interesting problems and exciting technologies. It is always easier to sell an engineer to come work with in-demand technology than a legacy or lesser known one.

Among the frontend frameworks, React.js still dominates the market. Within a year, Next.js has seen massive adoption.

web framework downloads

A comparison between number of downloads of gatsby (React.js), next (React.js), nuxt (Vue.js) framework , source

Since the pandemic, the Next.js framework has seen almost an 4x increase in number of downloads. The stats are only of downloads but I think this is a good signal that many people are using it or actively experimenting with it.

I only see this figure growing because Next.js is the best solution of this scale in this space right now. From a hiring perspective, this means that more and more talent are gravitating towards Next.js.

With Shopify announcing that they are working on their own Next.js like framework and platform (Hydrogen + Oxygen), this is a clear sign Next.js is moving in the right direction.

Do keep in mind, React.js has a total download numbers of ~11M. So, there is a big total addressable market - source.

Looking to the future

The Next.js team has recently announced exciting optimization improvements to their framework with webpack and swc.

Based on the pull requests, the team seems to be really betting on Rust for much of the tooling for the framework (Like many other projects).

I believe only more exciting things will come of this.

That said, there many similar, and competing platforms and frameworks that are also emerging all addressing similar needs:

  • Gatsby.js (React.js Based)
    • Gatsby cloud - edge computing (serverless functions)
    • streamlined CI/CD
    • Started to move from SSG to ISR (incremental static re-generation)
    • streamlined deploy and release workflow
    • plugin integrations
  • Remix (React.js Based)
    • Do not have too much details yet (Version 1.0 is to be released)
    • I think remix is platform agnostic and can deploy to various cloud providers
  • Hydrogen + Oxygen (React.js based) by shopify
    • Taking a bet on Server side components (React.js upcoming feature)
    • react-query, GraphQL, Vite, React.js server components
    • Oxygen seems to be Shopify’s edge computing solution
    • Possibly a competitor to Next.js + Vercel (unsure yet)
  • Netlify (Platform - supports React.js + other frameworks and languages)
    • Offers edge computing (serverless functions)
    • streamlined CI/CD

They all overlap in features and offering. I still believe Next.js is ahead in terms of the community adoption, it is the framework that offers the most versatility at this time.

Hydrogen and Remix may steal some of its market share in the future. However, Hydrogen was only recently announced, and Remix was closed source for the longest time until recently. So, we will see how things play out.

One thing is for sure though, it is an exciting time to be working in the React.js space right now. It is THE ecosystem to be in.

With various teams evolving and innovating on the meta frameworks, I am sure there will be more exciting things to come of this. Things like computing at the edge, developer experience improvements, optimizations, tooling and more!

References:


Enjoy the content ?

Then consider signing up to get notified when new content arrives!

Jerry Chang 2022. All rights reserved.