Skip to content
techpotions
Next.js · react · Web Development · framework comparison · SPA vs SSRNovember 2, 20267 min read

Next.js vs React: What You’re Actually Choosing

When you ask 'next.js vs react,' you're not comparing equals — you're choosing between a bare-metal UI library and an opinionated framework that wraps it in routing, server rendering, and deployment conventions.

Cover illustration for “Next.js vs React: What You’re Actually Choosing”

Next.js vs React: What You’re Actually Choosing

When you ask "next.js vs react," you’re not comparing equals — you’re choosing between a bare‑metal UI library and an opinionated framework that wraps it in routing, server rendering, and deployment conventions. React gives you the primitives (components, state, hooks) and lets you decide every other architectural detail. Next.js takes those primitives and adds a full‑stack chassis: a file‑based router, server‑side rendering (SSR), static generation, image optimization, API routes, and a single default deployment target. The real question is whether your product needs that chassis today, and what it will cost you later if you’re wrong.

Next.js vs React: What You Gain That React Alone Can’t Give You

Every React project eventually needs to answer the same infrastructure questions: routing, data fetching, SEO, performance. Next.js answers them out of the box. Here’s the breakdown.

Capability

Plain React (e.g., Vite / CRA)

Next.js

Routing

Manual setup with react-router or similar; no convention

File‑based routing (pages/ or app/); nested layouts, middleware

Rendering strategies

Client‑side only unless you build SSR/SSG yourself

SSR, SSG, ISR, and streaming out of the box, per‑page control

Data fetching

useEffect + fetch; no server‑side data loading setup

getServerSideProps, getStaticProps, server components, React cache

Image optimization

Manual <img> with no automatic resizing or lazy loading

<Image> component with automatic size‑aware generation and blur‑up

API layer

Separate backend or framework‑specific setup

API routes co‑located with frontend code (pages/api); edge functions

Deployment & hosting

Any static host; no built‑in SSR hosting

Optimized for Vercel, but deployable to Node.js or static hosts

JSX
// React + react-router: you define every route explicitly
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}
JSX
// Next.js: files become routes automatically
// pages/index.js   → /
// pages/about.js   → /about

export default function Home() {
  return <h1>Home</h1>;
}

These aren’t just convenience features. Contentful’s deep‑dive notes that Next.js “adds server‑side rendering, static site generation, automatic code splitting, and file‑based routing out of the box” — all things you’d otherwise have to stitch together. If you’re building a marketing site, an e‑commerce storefront, or any content‑rich app where SEO matters, Next.js removes months of tooling overhead.

The Trade‑offs: What You Take On When You Choose Next.js

Adopting Next.js means adopting an opinionated full‑stack model. That overhead is real and accumulates in three areas.

The server/client boundary becomes a discipline

React hooks and lifecycle work the same, but the mental model splits when rendering moves to the server. You can’t use useState or useEffect in a Server Component; data fetching moves to async components or dedicated server‑side functions. Every component now carries the implicit question: “Where does this code run?” The boundary forces you to think in a dual‑runtime architecture, which adds cognitive load and makes refactoring between client and server more delicate.

Framework upgrade cadence is not optional

React itself evolves slowly; Next.js ships frequently and deprecates patterns aggressively (think Pages Router → App Router, getInitialProps → getServerSideProps). A two‑year‑old Next.js project can feel like a legacy app if you haven’t kept pace with the migration paths. The framework’s tight coupling to Vercel’s runtime also means some features (Incremental Static Regeneration with on‑demand revalidation, edge middleware) work best on their platform — a lock‑in that’s comfortable until you want to leave.

Harder to extract later

React’s portability is one of its superpowers: a well‑factored React component can move between Vite, Next.js, Remix, or a custom setup. When you embrace Next.js‑specific APIs (server actions, getStaticProps, generateMetadata), you tie your logic to the framework. Migrating away later means rewriting those data‑flow seams, not just swapping a build tool. Think of it like choosing a Rails monolith over a Sinatra‑plus‑add‑ons: you get speed now but pay for decoupling later.

When Plain React (or Vite) Still Wins

Next.js isn’t the right default in every case. Several categories of applications get nothing but drag from the framework layer.

  • Internal dashboards and admin panels — no SEO requirement, often behind a login, and built by small teams that value radical simplicity. A Vite SPA with client‑side routing and a separate REST/GraphQL API gives you maximum agility.
  • Real‑time single‑page apps — heavy WebSocket or collaborative editing apps (think Figma, Notion) where the UI is a thick client. Server‑side rendering offers little benefit and can complicate real‑time state synchronization.
  • Projects where the frontend and backend teams are separate — Next.js blurs the line. If your backend is a gRPC service managed by a different team, forcing a co‑located API route pattern adds friction.
  • Rapid prototyping — when you need to validate an idea in days, not months. A <code>create‑vite</code> scaffold gets you to a working UI faster than learning Next.js conventions.

In all these cases, the React SPA approach (often with Vite) wins on speed of iteration and team independence. You avoid the framework upgrade treadmill and keep your skillset portable.

The Mixed Setup: Using Next.js as a Backend for a React SPA

If you’re starting with a React SPA but anticipate needing SSR or a dedicated API layer later, you don’t have to choose one world only. A productive middle ground is to keep your client app as a standalone SPA and mount it inside a Next.js shell.

JavaScript
// next.config.js — serve the SPA under /app while Next.js handles /api and marketing pages
module.exports = {
  async rewrites() {
    return [
      {
        source: '/app/:path*',
        destination: 'https://your-spa.netlify.app/:path*', // or proxy to a local SPA
      },
    ];
  },
};

This lets you use Next.js for server‑side rendered landing pages, API routes, and image optimization while the core product stays a plain React app. You get the SEO benefits where they matter without retrofitting your entire codebase. If the product outgrows the SPA, you can incrementally move pages into Next.js — a path we’ve walked with teams that started on Vite and later needed SSR (see our migration guide for the playbook).

The Refactoring Cost If You Pick Wrong at the Start

Choosing incorrectly at day one doesn’t just mean a migration later — it means shipping the wrong architecture while the product is finding product‑market fit. A team that builds a content‑focused site as a pure SPA will hit an SEO wall and have to re‑architect data fetching, routing, and rendering when traffic depends on organic search. Conversely, a team that picks Next.js for a real‑time dashboard will spend cycles fighting the server/client boundary with no payoff.

A full SPA‑to‑Next.js migration isn’t just swapping build tools. It involves:

  • Converting client‑side routing (react‑router) to file‑based pages
  • Moving data fetching from useEffect to getServerSideProps or server components
  • Replacing hand‑rolled image loading with <Image />
  • Restructuring state management to work across SSR hydration boundaries

The effort can easily match the time it took to build the original app, especially if the codebase wasn’t structured for separation of concerns. That’s why we recommend teams make the next.js vs react decision early, based on the product’s likely needs at 10k users, not just the first prototype. If you’re unsure, our web engineering team often helps startups run a one‑week spike with both stacks to test the real trade‑offs before committing.

FAQ

Is Next.js just React with extras?

No, Next.js is a framework that uses React for UI but adds a compilation layer, server‑side runtime, and conventions that fundamentally change how you build and deploy. React gives you a toolbox; Next.js gives you the pre‑assembled workbench with routing, rendering strategies, and deployment targets already wired together.

Can I migrate an existing React SPA to Next.js gradually?

Yes, you can mount an existing React SPA inside a Next.js project by serving it from a catch‑all route while building new pages with Next.js filesystem routing. Full integration, though, usually means rethinking data fetching and routing — a process we detailed in our next.js vs vite migration guide.

Does Next.js lock you into Vercel?

Next.js can be deployed anywhere that runs Node.js or static hosting; you aren’t forced onto Vercel. However, the framework’s tight integration with Vercel’s edge functions and analytics can make the managed platform appealing if you’re already using Next.js.

Written by
techpotions
All entries
Next.js vs Nest.js: One Serves Pages, One Serves APIs
The weekly

One email a week, from the workshop.

What we published, what we shipped, and the free packs as they land. No drip sequence, no webinar, unsubscribe in one click.