Tech stack
·12 min read

Next.js vs. React: Differences and How to Choose

Facebook released React in 2013, and it’s not an exaggeration to say that it took the web development industry by storm and has completely transformed how we build websites and web applications.

Not only is React an extremely popular and highly adopted JavaScript framework, but React-powered meta-frameworks have also made an enormous impact in the front-end development space. One React-powered powered framework that stands, in particular, is Next.js. It builds upon React’s foundation by offering features like Server-side rendering (SSR), file-based routing, middleware, and API routes.

In this article, we will explore React and Next.js in detail, their features, pros, cons, use cases, and differences.

Since Next.js is built on React, this is not an apples-to-apples comparison. However, comparing them will help us better understand their differences and which to use in certain scenarios.

Let’s dive in.

What is React?

React started as an internal tool at Meta (prev Facebook) until they released it to the public in 2013. It is an open-source JavaScript library for building everything from simple user interfaces to large-scale, interactive websites and web applications. React also supports the development of iOS and Android apps with React Native, its cross-platform mobile development framework.

React’s impact on the web development industry is undeniable. It has transformed how we build applications and has led to the creation of multiple React-powered frameworks like Next.js, Gatsby, and Remix.

Over 13.8 million websites use React, including Airbnb, Doordash, Lyft, Dropbox, and Zoom.

Features of React

Virtual Document Object Model (DOM)

The virtual DOM is a lightweight copy of the actual DOM, which allows React to update and render components efficiently. Instead of making changes directly to the real DOM, React compares the virtual DOM with the actual DOM and only updates the necessary parts. This makes React fast and efficient, especially for large and complex applications.

JSX syntax

React uses the JSX (JavaScript Syntax Extension) syntax, which allows us to write HTML-like code inside JavaScript files. JSX makes it easier to define and manipulate components, as it combines the power of JavaScript with the simplicity of HTML.

Although many developers initially pushed against JSX because it went against the principle of “separation of concerns,” people have grown to like or at least operate it over time.

Here’s a sample of React’s JSX code:

function JsxExample() {

  const name = "John";

  return (
    <div>
      <h1 clasName="red-herring">Hello {name}!</h1>
      <p>JSX allows us to write Javascript and HTML together.</p>
      
      <img 
        src="image.png" 
        width="100px"
        alt="React Image">
      </img>

      <button onClick={() => alert('Clicked!')}>
        Click Me
      </button>
    </div>
  );
}

export default JsxExample;

Component-based architecture

React allows us to break down user interfaces into small, self-contained components. We can then reuse these components throughout an application. Each React component can have its own state, props, and functionality, making it easy to manage and update specific parts of the application without affecting the whole.

React’s component-based architecture enhances code reusability, maintainability, and scalability.

The code snippet below helps illustrate React’s modular approach.

// Header.js
export default function Header() {
  return (
    <header>
      <h1>My Website</h1>
      <p>Welcome!</p> 
    </header>
  );
}

// Blog.js
export default function Blog() {
  return (
    <main>
      <p>This is the content section.</p>  
      <article>
        <h3>Hello World</h3>
        <p>React is great!</p>  
      </article>
    </main>
  );  
}

// App.js
import Header from './Header'; 
import Blog from './Blog';

function App() {
  return (
    <div>
      <Header />
      <Blog />
    </div>
  );
}

export default App;

Built-in state management

React provides three built-in state management solutions: the useState hook for local state, the Context API for global state management, and the useReducer hook, a more advanced form of useState.

  • The useState hook: one of several hooks react offers. It provides a state variable that allows us to track a component’s state and a function to update said state.
  • The useReducer hook: an alternative to useState and is particularly useful for managing complex state logic.
  • The Context API: for creating global states that we can access anywhere in an application. It requires the createContext function and the useState and useContext hooks to function.

Here’s a simple counter app that uses the useSate hook for local state management.

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(prevCount => prevCount + 1);
  }
  
  const decrement = () => {
    setCount(prevCount => prevCount - 1);
  }

  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>  
      <button onClick={increment}>+</button>
    </div>
  );
}

export default Counter;

React’s built-in state management solutions may be inadequate for large-scale apps with multiple states that must be in sync with user interactions and UI changes. We can use state management libraries like Jotai and Zustand in such cases.

Deliver a fast website with a visual Page Builder

Prismic is a headless solution, with a visual Page Builder for your marketing team to release pages independently.

Advantages of React

Performance optimization

React provides several techniques for optimizing the performance of applications to make them faster and more responsive, including:

  • Virtual DOM: As mentioned earlier, the VDOM ensures efficient updates and rendering
  • React.memo: A higher-order component that wraps around other components to memoize them and prevent unnecessary renderings
  • Lazy loading: It defers loading a component’s code until it is rendered for the first time
  • Suspense component: allows us to show fallback content (e.g., a loading indicator) while its children components are loading

Rich ecosystem

React has a large and active community of developers, meaning there is a wealth of resources, libraries, and support that help us develop applications more effectively and extend their functionality.

React’s community has created tools like Framer Motion, Jotai, Next.js, Chakra UI, and Remix. In fact, there are few scenarios where you won’t find a third-party solution for your project. Check out Awesome React, a collection of great sources in React’s ecosystem.

Android and iOS mobile app development

One of the advantages of being a React developer is that we can apply our React knowledge to create mobile applications using React Native.

React Native is an open-source and cross-platform React-based framework developed by the React team for building iOS and Android apps. This means that we don’t need to learn other languages like Flutter or Kotlin to build mobile apps.

Disadvantages of React

Relies on third-party tools

React is a library for building user interfaces, not a framework, meaning that it does not provide built-in solutions for routing, animations, etc.

React's nature of being an opinionated library allows us to integrate our preferred third-party solutions. However, this makes the development process tricky as we have to vet many third-party solutions.

React's dependence on third-party tools also affects developers who get new jobs because they must constantly learn a different tech stack.

Fragmented community

React has a large and active community, which is generally a positive thing. However, this also means that there are multiple libraries, frameworks, and tools built around React, each with its own approach and best practices. This fragmentation can make choosing the right tools and staying updated with the latest trends in the React ecosystem difficult.

React Use cases

Single-page applications (SPAs)

React is well-suited for developing SPAs, which provide a seamless user experience by dynamically updating content without the need for page reloads. With React, developers can create highly interactive and responsive SPAs that offer a native-like feel.

Progressive web apps (PWAs)

PWAs combine the best features of web and mobile applications, providing an app-like experience within a web browser. React can be used to build PWAs that are fast, reliable, and responsive, regardless of the device or network conditions. React's component-based architecture and state management capabilities make it an excellent choice for developing PWAs.

How to get started with React

The React team recommends using one of the React-powered frameworks for new React applications. However, if we want to use just React, we can quickly spin up a new React project with Vite.

First, run the command below to install Vite’s latest version.

npm create vite@latest

After that, give the project a name and select react as the framework.

An image of terminal options in react project.

Next, run the commands below in sequence to navigate into the folder, install the necessary dependencies, and start the server.

cd vite-project
npm install    
npm run dev
An image of Vite and React project.

What is Next.js?

Next.js is an open-source React-powered framework for creating performant websites and applications. It was built by Vercel and has grown in popularity since its release in 2016.

A major season behind Next.js’ rise to fame is its built-in SSR functionality. This allows developers to create fast-loading websites. The SSR feature also makes Next.js an SEO-friendly framework, which is why developers often use it to build blogs and landing pages.

Next.js is widely adopted by many businesses and the developer community. Companies like Loom, Target, TikTok, and The Washington Post use Next.js for their websites.

Features of Next.js

Server-side rendering (SSR)

Server-side rendering allows us to pre-render the HTML on the server and send it to the client. This means that users who visit a Next.js-powered website will see the fully rendered content immediately without waiting for JavaScript to load.

To use SSR for a page, we need to export getServerSideProps, an async function that the server will call on every request.

Here’s an example of how this looks in code:

export default function Page({ data }) {
  // Rrender data...
}
 
// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()
 
  // Pass data to the page via props
  return { props: { data } }
}

Static-site generation (SSG)

Static-site generation generates HTML files during the build phase, which are then served to the client as static files. This means every page is pre-rendered and ready to be served instantly without the need for server-side processing.

SSG is good for content that doesn’t change often, like blogs and documentation. By default, Next.js pre-renders pages using SSG.

Server-side rendering vs. static site generation

Explore this article to learn the differences between server-side rendering and static site generation.

Image optimization

Next.js provides built-in image optimization via a custom image component called next/image. This custom image component is a wrapper around the standard HTML img element. The only difference is that next/image automatically handles image optimization, allowing us to focus on other development tasks.

The benefits of the image component include:

  • It automatically serves images in next-gen image formats like WebP and AVIF, ensuring optimum performance and fast loading times
  • Provides lazy loading and image blur while loading
  • Avoids Cumulative Layout Shift (CLS) while rendering the images, leading to better Core Web Vitals (CWV)
  • Allows us to serve responsive images by defining custom breakpoints through its sizes prop

Here’s a sample code of Next.js’ image component in action.

import Image from "next/image"
import profileImg from "../public/profile.png"

const Profile = () => {
  return (
    <>
      <h1> User Profile </h1>
      <Image
        src={profileImg}
        alt="user profile image"
        width={300}
        height={300}
        loading="lazy"
        placeholder="blur"
        sizes="(min-width: 60em) 24vw, (min-width: 28em) 45vw, 100vw"
      />
    </>
  )
}

Prefetching

Prefetching is a feature of Next.js’ routing and navigation system, and it is built into the custom Link component. Once a route is inside the viewport, Next.js automatically starts loading the resources for that route in the background.

This means that when a user finally clicks on a prefetched route, the route will load faster because the necessary resources are already available.

Font optimization

Next.js provides a font package, next/font, which automatically optimizes fonts and eliminates external network requests for improved privacy and performance. The next/font package works with Google, custom, and local fonts.

Benefits of next/font include:

  • Automatic font optimization
  • Improves website performance
  • Supports Google fonts and local font
  • Built-in automatic self-hosting for font files, which eliminates layout shift

Here’s a sample code of next/font in action.

import { Inter, Roboto_Mono } from "next/font/google"

export const inter = Inter({
  subsets: ["latin"],
  display: "swap",
})

export const roboto_mono = Roboto_Mono({
  subsets: ["latin"],
  display: "swap",
})

export default function RootLayout({ children }) {
  return (
    <div>
      <h1 className={inter.className}>Styled with Inter font</h1>
      <h1 className={roboto.className}>Styled with Roboto font</h1>
    </div>
  )
}

Script optimization

Next.js provides a next/script package for loading third-party scripts. The package optimizes scripts by ensuring that scripts only load once, even if a user navigates between multiple routes.

next/script provides the following script loading strategies:

  • beforeInteractive: Load the script before page hydration occurs and before any Next.js code loads
  • afterInteractive: Load the script after some page hydration occurs. This is the default strategy
  • lazyOnload: Load the script later while the browser is idle
  • worker: Load the script in a web worker. This strategy is still experimental

Here’s a sample code for next/script:

<Script
  src="https://product-gallery.cloudinary.com/all.js"
  type="text/javascript"
  strategy="beforeInteractive" //this has to be the strategy
/>

Route Handlers

Route Handlers are functions that allow us to handle HTTP requests, run server-side code in our application, and perform tasks like fetching data from a database, handling user authentication, or integrating with external APIs.

Route Handlers support all of the major HTTP methods like GET and POST. To use Route Handlers, we must define them in a route.js file inside the app directory:

export async function GET() {
  const res = await fetch('https://data.mongodb-api.com/...', {
    headers: {
      'Content-Type': 'application/json',
      'API-Key': process.env.DATA_API_KEY,
    },
  })
  const data = await res.json()
 
  return Response.json({ data })

React Server Components

React Server Components (RSC) allows us to create async components that get pre-rendered on the server and sent to the client as reusable, interactive units.

Like regular React components, Server components can import client components, render them, and pass data to them through props. However, client components cannot import server components. This means that it's better to place server components at the top of the component tree.

With RSC, components are near the data source. This eliminates trips between unnecessary client-server trips and speeds up operations like data fetching and database mutations.

Note that server components cannot access the browser or cannot perform client-side operations. This means we can't use hooks like useState and useEffect.

Here’s a sample code of RSC in action.


import { getProductsFromDB } from './services/mongo'

export default async function Products() {
  const allProducts = await getProductsFromDB.find();

  return (
    <>
      <h1>Products</h1>

      {data.map((product) => (
        <div key={product.id}>
          <h2>{product.title}</h2>
          <p>{product.description}</p>
        </div>
      ))}
    </>
  )
}

Strictly speaking, RSC is a feature of React.js. However, it requires a server system like Next.js provides. That’s why we’re covering it under Next.js.

Advantages of Next.js

Improved performance

By implementing SSR, Next.js generates HTML on the server and sends it to the client, resulting in faster page loading times. This is especially beneficial for content-heavy websites or applications that require frequent data updates.

Besides SSR, Next.js’ built-in image, script, and font optimization features further improve performance.

SEO-friendly

Next.js’ SSR capabilities make it SEO-friendly. SSR enables search engines to crawl and index the content of our websites effectively, leading to better search engine rankings. This is crucial for businesses that rely on organic traffic to drive their online presence and generate leads.

How Next.js helps with SEO

Want to learn more about how Next.js can improve your SEO performance and help you rank higher on search engines? Explore our article that goes into this subject in greater detail.

Stay on Top of New Tools, Frameworks, and More

Research shows that we learn better by doing. Dive into a monthly tutorial with the Optimized Dev Newsletter that helps you decide which new web dev tools are worth adding to your stack.

Code splitting

Next.js enables automatic code splitting, which loads only the necessary JavaScript code for each route. This feature improves performance by reducing the initial load time, ensuring users get a fast and seamless experience, regardless of their device or network conditions.

Great development experience

Next.js offers a great developer experience, improves productivity, and shortens development time by:

  • Providing several built-in features like routing, SSR, and resource optimizations, allowing us to focus on more critical tasks
  • Offering comprehensive documentation that improves the learning experience
  • Providing TypeScript support, which allows us to write type-safe code

As someone who learned Next.js after years of working with React, I was shocked to see how Next.js’ built-in features streamlined my development experience and helped me become more productive.

Disadvantages of Next.js

No built-in state management

Unlike frameworks like Angular, Next.js does have a built-in state management solution. That means we must use third-party libraries like MobX, Jotai, and Recoil. Configuring and integrating these libraries can further complicate the development process.

Next.js Use cases

Blogs, news websites, and media publications

Next.js’ built-in SSR support makes it a great choice for blogs, news websites, and media publications because these projects need fast-loading pages and high search engine visibility. It is also an excellent choice for ecommerce websites that require real-time updates.

Also, Next.js integrates seamlessly with headless website builders like Prismic, which allows us to create unique websites that leave a lasting impression on visitors. Prismic’s Page Builder and slices also empower marketers and content teams to launch pages, update content, and run time-sensitive campaigns with minimal dependence on developers.

Marketing Websites and landing pages

Next.js is a great choice for marketing websites and landing pages for the following reasons:

  • Leads to fast-loading websites
  • Provides greater search engine visibility due to SSR
  • Optimizes the loading of third-party libraries like Google Tag Manager, which are important for tracking the analytics and success of marketing campaigns
  • Seamlessly integrates with headless solutions, which enables marketers and editors to launch new pages and keep campaign messages up-to-date

Paddle, a billing solution for SaaS companies, used Prismic and Next.js to build its website.

An image of the Paddle website.

E-commerce websites

The performance and SEO benefits Next.js provides make it a great tool for e-commerce websites. We can use Next.js to offer online shoppers a great user experience while ensuring high conversion rates.

Pairing Prismic with Next.js allows The Container Store to meet its performance and SEO goals, leading to high SERP rankings for tens of target keywords.

An image of the Container Store website.

How to get started with Next.js

First, run the command below in your terminal to install Next.js.

npx create-next-app@latest

After that, configure the Next.js project to fit your development workflow.

An image of the Next.js terminal interface.

After that, configure the Next.js project to fit your development workflow.

Next, navigate into the project’s directory, start the dev server, and start building!

cd name-of-project
npm run dev
An image of the Next.js site front-end.

Ready to start building with Next.js?

Create a free Prismic account to start building with Next.js and Prismic, or kick-start your project with these 9 great Next.js boilerplates you can use for your next project.

Differences between React and Next.js

Library vs framework

One of the key differences between React and Next.js is that React is a JavaScript library, while Next.js is a full-fledged framework.

As a library, React handles only the view layer of an application. It focuses on the user interface and updates it as users interact and perform actions. React is unopinionated and doesn't dictate how we manage other aspects like routing, data fetching, API handling, and testing.

Unlike React, Next.js is an opinionated framework that provides the tools needed to build production-ready apps. It handles routing, server-side rendering, static site generation, image and font optimization, and more out of the box. Next.js’ opinionated approach reduces decision paralysis and allows us to build faster.

SEO-friendliness

Websites built with React struggle with search engine visibility because React uses client-side rendering. This means that bots and web crawlers index empty HTML shells at the first pass, leading to low SERP rankings.

Building websites with Next.js allows us to enjoy high search engine visibility, thanks to its SSR capability, which allows search engine crawlers to better understand a page’s content and index it properly.

Optimization features

React provides built-in optimization features like the useMemo hook, memo function, lazy function, and Suspense.

Being a React-based library, Next.js has access to React's optimization features added to the built-in tools it provides, including code splitting, prefetching, and optimization for images, fonts, and third-party scripts. Building websites with Next.js allows us to enjoy the best of both worlds and reduces our dependency on third-party optimization tools and libraries.

Routing

React doesn't provide a built-in tool for handling page navigation and routing. This means that we have to integrate third-party libraries like React Router for navigation in React applications.

Next.js provides a built-in file-based routing system, meaning we don’t need external tools. Part of the navigation system is a Link component that prefetches routes, which elevates the user experience by making navigation between pages appear instantaneous to web visitors.

The built-in routing system streamlines the development process, especially for applications that involve multiple pages.

Developer community

React has a larger and more established community than Next.js, one reason being that React was released in 2013, while Next.js was released in 2016. React is one of the most popular JavaScript libraries today, and its developer community constantly releases new third-party solutions, learning resources, and templates.

While Next.js is younger than React, it isn’t slacking when it comes to community. Next.js provides a rich developer experience and comes with several amazing features. It is currently one of the most popular React-powered frameworks available. Besides great features, other factors that come into play include:

  • Being backed by Vercel
  • A solid and well-structured documentation
  • A detailed and interactive learning platform
  • Developer conferences like the annual Next.js Conf
  • A great and active team of developer advocates that constantly engages the community; shoutout to Lee Robinson

TL;DR - React vs. Next.js

Library vs framework

Library

Framework

SEO-friendly
React: No
Next.js: Yes
Built-in routing
React: No
Next.js: Yes
Mobile app development
React: Yes
Next.js: No
Server-side rendering
React: No
Next.js: Yes
GitHub stars

216k

116k

Built-in optimization tools

Optimization tools include useMemo hook, memo function, VDOM, <suspense/>, and the lazy loading function

Optimization tools include route prefetching, code splitting, and image, font, and third-party script optimization

Conclusion

In summary, React and Next.js both have unique strengths that make them suitable for different projects.

React is a flexible JavaScript library focused purely on building user interfaces, while Next.js is an opinionated framework that builds on React and provides extra functionality like server-side rendering and optimization features out of the box.

When choosing between them, consider factors like the nature of your application, whether SEO is a priority, your team's existing knowledge, and the level of flexibility you need. For marketing sites, blogs, or content-heavy pages where performance and SEO matter most, Next.js is likely the better fit. React may be preferable for complex interactive apps where flexibility and control are critical.

Ultimately, neither is objectively "better" as they aim to solve different problems. Next.js makes it faster to build production-ready apps by providing conventions and pre-built solutions. React offers more customization and control for developers who want to handpick all their dependencies.

Understanding their differences allows us to make informed decisions about which tool to use.

Try editing a page with Prismic

A visual page builder, configured to marketing team's needs. They can easily create on-brand website pages, release more, attract more visitors and convert quality leads.

FAQs

Is Next.js required for React?

No. You don’t need Next.js to work with React because it is not a React dependency. Instead, the reverse is the case, as Next.js is built on top of React and needs React to function.

Article written by

Nefe Emadamerho-Atori

Nefe is an experienced front-end developer and technical writer who enjoys learning new things and sharing his knowledge with others.

More posts
Nefe Emadamerho-Atori

Join the discussion

Hit your website goals

Websites success stories from the Prismic Community

How Arcadia is Telling a Consistent Brand Story

Read Case Study

How Evri Cut their Time to Ship

Read Case Study

How Pallyy Grew Daily Visitors from 500 to 10,000

Read Case Study