React vs Next.js: When to Use Each (A Developer's Honest Take)
“Should I use Next.js?” is one of the most common questions we get from clients and developers starting new projects. The answer, like most things in software, is “it depends” — but we can make that answer a lot more specific.
We’ve shipped production applications with both plain React (via Vite) and Next.js across a range of project types. This isn’t a feature comparison you can read in the docs. It’s a practical guide based on what we’ve learned about where each tool shines and where it creates unnecessary complexity.
The Core Difference: Rendering Strategy
React is a UI library. It gives you components, state management, and a rendering engine. By default (with Vite or Create React App), it produces a Single-Page Application (SPA) — a bundle of JavaScript that runs entirely in the browser.
Next.js is a framework built on React. It adds server-side rendering (SSR), static site generation (SSG), file-based routing, API routes, and a growing list of features around React Server Components. The key addition is that Next.js can render your React components on the server and send HTML to the browser.
This distinction has cascading implications for performance, SEO, deployment, and developer experience.
When to Use Plain React (Vite)
Authenticated Applications and Dashboards
If your entire application is behind a login screen, SEO doesn’t matter and the initial load penalty of an SPA is a one-time cost. Dashboards, admin panels, internal tools, and SaaS products where users are logged in for extended sessions are ideal SPA territory.
A React + Vite setup gives you:
- Faster development iteration. Vite’s hot module replacement is nearly instant. No server restarts, no hydration mismatches to debug.
- Simpler mental model. Everything runs in the browser. State is client-side. Data fetching happens in components or hooks. There’s no question about where code executes.
- Simpler deployment. An SPA is a folder of static files. Deploy to any CDN, S3 bucket, or static host. No server infrastructure to manage.
Applications With Complex Client-Side Interactivity
Real-time collaboration tools, interactive data visualizations, drag-and-drop interfaces, canvas-based applications — these are inherently client-side. Server rendering adds complexity without meaningful benefit because the interesting parts of the UI require JavaScript anyway.
When Your Team Knows React But Not Next.js
This matters more than people admit. Next.js has a substantial learning curve beyond React: the App Router vs Pages Router distinction, server vs client components, caching behavior, middleware, route handlers, and server actions all add concepts that take time to master.
If your team is productive with React and Vite, and your project doesn’t require SSR or SSG, introducing Next.js adds overhead without proportional benefit.
When to Use Next.js
Content-Heavy Sites That Need SEO
Marketing sites, blogs, e-commerce storefronts, documentation sites — anything where search engine visibility is critical. Server-rendered HTML is immediately crawlable by search engines. SPAs can be crawled (Google’s crawler executes JavaScript), but SSR is more reliable and produces better Core Web Vitals scores.
That said, if your project is purely content-focused with minimal interactivity, consider whether Next.js is even the right tool. Static site generators like Astro produce faster sites with less JavaScript for content-first projects. We use Astro for most content sites, including this one.
Applications That Benefit From Server-Side Data Fetching
Next.js shines when your pages need data that’s available on the server — database queries, authenticated API calls, content from a CMS. Server Components let you fetch data directly in your component tree without exposing API endpoints or managing client-side loading states.
For example, a product page that needs to fetch inventory data, pricing, and reviews can do all of that server-side and send a fully rendered page to the browser. The user sees content immediately instead of watching loading spinners.
Full-Stack Applications Where You Want One Codebase
Next.js API routes (or Route Handlers in the App Router) let you build backend endpoints alongside your frontend code. For small to medium applications, this eliminates the need for a separate backend service.
We’ve built several internal tools and SaaS products where a Next.js monolith was the right choice — the team could deploy one application instead of coordinating frontend and backend deployments separately.
Applications That Need Edge or Middleware Logic
Next.js middleware runs before a request reaches your page, enabling authentication checks, redirects, A/B testing, and geolocation-based routing at the edge. If your application needs request-level logic, Next.js provides a natural place for it.
Performance: The Nuanced Truth
The common claim is “Next.js is faster because of SSR.” This is an oversimplification.
First Load: Next.js Usually Wins
For the first page a user visits, server-rendered HTML appears faster because the browser can paint content before JavaScript loads. A well-optimized Next.js page will have better Largest Contentful Paint (LCP) and First Contentful Paint (FCP) than an equivalent SPA.
The margin depends on your page’s JavaScript weight. If your SPA is 150kb of JavaScript, the difference is small. If it’s 800kb (common with large component libraries and data fetching dependencies), the difference is significant.
Subsequent Navigation: React SPA Usually Wins
After the initial load, an SPA has all its code cached in the browser. Navigation between pages is instant — there’s no server round-trip. Next.js mitigates this with client-side navigation and prefetching, but the SPA model is inherently faster for in-app transitions because there’s no server involved.
Total JavaScript: It’s Complicated
A common misconception is that Next.js reduces JavaScript. It doesn’t — it changes when JavaScript loads. A Next.js page still hydrates in the browser, meaning the full React component tree eventually loads as JavaScript. Server Components (RSC) change this equation by keeping some components server-only, but RSC introduces its own complexity.
In practice, we’ve seen Next.js applications ship more total JavaScript than equivalent Vite SPAs because of the hydration runtime, router code, and RSC payload format. The perceived performance is often better because of streaming and progressive loading, but the total bytes transferred are not necessarily fewer.
Deployment Complexity: A Real Consideration
React + Vite
Deploy anywhere that serves static files. Netlify, Vercel, Cloudflare Pages, AWS S3 + CloudFront, a $5/month VPS. No runtime to manage, no server to keep alive. You can deploy a Vite React app with a drag-and-drop to Netlify in 30 seconds.
Next.js
The deployment story depends on which Next.js features you use:
- Static export only (SSG): Deploys like a static site. No server needed. But if you’re only using SSG, you’re paying the Next.js complexity tax without using the features that justify it.
- SSR / API Routes / Server Components: Requires a Node.js server or a platform that supports Next.js’s server runtime. Vercel is the native home for Next.js (they build it), and deploying there is seamless. Deploying elsewhere — AWS, self-hosted, Docker — requires more configuration.
- Edge Runtime / Middleware: Requires a platform that supports edge functions. Vercel and Cloudflare handle this. Self-hosting edge functions is not straightforward.
This isn’t a dealbreaker, but it’s a real operational consideration. We’ve had clients who chose Next.js for a project, then discovered their hosting environment didn’t support SSR, forcing a rewrite to static export that negated the reason they chose Next.js.
Real Project Examples
Dashboard Application: React + Vite Was the Right Call
A client needed an admin dashboard for managing customer accounts, viewing analytics, and configuring their SaaS product. Every user was authenticated. SEO was irrelevant. The UI was heavily interactive with real-time data updates.
We built it with React, Vite, React Query for data fetching, and Tailwind for styling. Deployment was a static build to Cloudflare Pages. The development experience was fast, the deployment was trivial, and the application performed well because there was no SSR complexity to manage.
E-Commerce Storefront: Next.js Made Sense
A different client needed a custom storefront connected to a headless CMS. Product pages needed to be crawlable by search engines, product data came from an API that required server-side authentication, and they wanted preview mode for content editors.
Next.js was the right choice. Server-side rendering gave us SEO. Server Components let us fetch product data without exposing API keys. The preview mode API let content editors see draft changes before publishing.
Marketing Site: Neither Was the Best Choice
A startup needed a marketing site with a blog, team page, and contact form. No authenticated features, no dynamic data, no complex interactivity.
We built it with Astro. Zero JavaScript shipped to the browser by default, sub-second page loads, and a perfect Lighthouse score. Both React and Next.js would have been overkill.
Decision Framework
Here’s the framework we use when helping clients choose:
Use React + Vite when:
- Your app is behind authentication
- SEO doesn’t matter for your use case
- Your UI is heavily interactive (real-time features, complex state, canvas/WebGL)
- You want the simplest possible deployment
- Your team knows React but not Next.js
Use Next.js when:
- You need server-side rendering for SEO
- Your pages depend on server-side data (database queries, authenticated APIs)
- You want a full-stack monolith (frontend + API in one codebase)
- You need middleware for auth, redirects, or A/B testing
- You’re deploying to Vercel or a platform with good Next.js support
Use neither (consider Astro or another SSG) when:
- Your site is primarily content with minimal interactivity
- Performance is critical and every kilobyte of JavaScript matters
- You don’t need React’s component model for most of your pages
The Bottom Line
Next.js is not “better React.” It’s React plus a server framework, and that server adds both capability and complexity. The question isn’t which is better — it’s whether the capabilities justify the complexity for your specific project.
We’ve seen teams adopt Next.js because it’s popular, then spend weeks debugging hydration mismatches, caching issues, and deployment problems they wouldn’t have had with a simpler setup. We’ve also seen teams stick with SPAs when SSR would have solved real SEO and performance problems.
The right tool depends on the job. If you’re starting a project and want help making this decision, reach out to us. We’ll look at your requirements and give you an honest recommendation — even if that recommendation is “use a tool we don’t specialize in.” You can learn more about how we approach technical decisions on our about page.
Related reading
Ready to work together?
Get in Touch