Next.js vs React: Core Concepts Comparison

Introduction

React is a JavaScript library for building user interfaces, while Next.js is a React framework that adds powerful features like server-side rendering, routing, and optimizations on top of React.


1. Project Setup

React

npx create-react-app my-app

Next.js

npx create-next-app my-app

2. Routing

React

// React with React Router
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

Next.js

// Next.js - File structure creates routes
// pages/index.js → /
// pages/about.js → /about
// pages/blog/[id].js → /blog/:id

// pages/index.js
export default function Home() {
  return <h1>Home Page</h1>;
}

3. Rendering Methods

React

// Standard React component (CSR)
function MyComponent() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then(setData);
  }, []);
  
  return <div>{data?.title}</div>;
}

Next.js

Supports multiple rendering strategies:

1. Static Site Generation (SSG)

// getStaticProps runs at build time
export async function getStaticProps() {
  const data = await fetch('https://api.example.com/data');
  return { props: { data: await data.json() } };
}

export default function Page({ data }) {
  return <div>{data.title}</div>;
}

2. Server-Side Rendering (SSR)

// getServerSideProps runs on every request
export async function getServerSideProps() {
  const data = await fetch('https://api.example.com/data');
  return { props: { data: await data.json() } };
}

3. Client-Side Rendering (CSR)

4. Incremental Static Regeneration (ISR)

export async function getStaticProps() {
  const data = await fetch('https://api.example.com/data');
  return {
    props: { data: await data.json() },
    revalidate: 60 // Regenerate every 60 seconds
  };
}

4. Data Fetching

React

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>Loading...</div>;
  return <div>{user.name}</div>;
}

Next.js

// Next.js App Router (modern approach)
async function UserProfile() {
  const user = await fetch('/api/user').then(r => r.json());
  return <div>{user.name}</div>;
}

// Or with Pages Router
export async function getServerSideProps() {
  const user = await fetch('/api/user').then(r => r.json());
  return { props: { user } };
}

export default function UserProfile({ user }) {
  return <div>{user.name}</div>;
}

5. API Routes

React

// Separate backend required
// Must set up Express server separately
const express = require('express');
const app = express();

app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

Next.js

// pages/api/users.js
export default function handler(req, res) {
  res.status(200).json({ users: ['Alice', 'Bob'] });
}

// Access at: /api/users

6. Image Optimization

React

// React
function MyImage() {
  return <img src="/photo.jpg" alt="Photo" />;
}

Next.js

// Next.js
import Image from 'next/image';

function MyImage() {
  return (
    <Image
      src="/photo.jpg"
      alt="Photo"
      width={500}
      height={300}
      placeholder="blur"
    />
  );
}

7. Code Splitting

React

// React
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

Next.js

// Next.js - automatic per-page code splitting
// Each page only loads its own JavaScript

// Dynamic import when needed
import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(() => import('./Component'), {
  loading: () => <p>Loading...</p>
});

8. SEO and Meta Tags

React

// React with React Helmet
import { Helmet } from 'react-helmet';

function Page() {
  return (
    <>
      <Helmet>
        <title>My Page</title>
        <meta name="description" content="Page description" />
      </Helmet>
      <h1>Content</h1>
    </>
  );
}

Next.js

// Next.js Pages Router
import Head from 'next/head';

export default function Page() {
  return (
    <>
      <Head>
        <title>My Page</title>
        <meta name="description" content="Page description" />
      </Head>
      <h1>Content</h1>
    </>
  );
}

// Next.js App Router
export const metadata = {
  title: 'My Page',
  description: 'Page description'
};

9. Styling Options

React

Next.js

// Next.js CSS Modules
import styles from './Button.module.css';

export default function Button() {
  return <button className={styles.primary}>Click me</button>;
}

10. Performance Optimization

React

Next.js


11. Deployment

React

Next.js


When to Use Each

Use React When:

Use Next.js When:


Key Takeaways

React is a library focused on building user interfaces with a component-based approach. It gives you flexibility but requires more setup and configuration.

Next.js is a full-featured framework built on React that provides:

Next.js extends React's capabilities while maintaining React's core principles, making it ideal for production applications that need SEO, performance, and developer experience.