After 20+ client projects on Next.js, I switched most of my work to Vite + React. The honest reason: most clients don't need SSR, and Next.js makes you pay for SSR even when you're not using it - in build time, in deployment complexity, in mental overhead, and in money. Vite gives me sub-second dev server starts, smaller bundles, deploy-anywhere flexibility, and a stack a junior can hand off in a week. I still reach for Next.js when SEO, edge rendering, or co-located backend code is genuinely the requirement. The rule I now use is: pick the simplest tool that solves the actual problem in front of you, not the most powerful tool in case the problem grows.
I've been a Next.js advocate for years. Server-side rendering, file-based routing, API routes, image optimization, the App Router - it's a powerful framework, and Vercel has done a remarkable job of pushing the web forward through it. For long-form content sites, marketing pages, and large multi-tenant SaaS, it's an excellent default.
But after shipping more than twenty client projects across portfolios, dashboards, admin panels, internal tools, and small SaaS products, I noticed an uncomfortable pattern: almost none of my clients actually needed SSR. They needed a fast app, a clean handoff, cheap hosting, and a stack their next developer could understand without a course.
What they were getting was an SSR-shaped framework that added complexity I had to keep explaining away. The first time I shipped a Vite + React + Supabase project end to end and watched the dev server boot in 200ms and the production build deploy to a static host for free, I stopped pretending. For SPAs, Next.js is overkill, and the overkill has a cost.
Next.js is built around the assumption that some pages will be server-rendered. Even if you push everything to the client, you're still inside that assumption. You pay for it in:
None of this is fatal. A lot of it is acceptable for the right project. But for an SPA that's going to live behind auth and ship to a handful of users, every one of those costs is being paid for a benefit that's never collected.
Build speed. Vite's dev server starts in under 300 milliseconds on my machine. Cold start. Next.js takes between 3 and 8 seconds on the same hardware. When you're iterating fast - making a small change, checking the browser, making another small change - that gap compounds into real wall-clock hours over a week of work.
Simplicity. There is no getServerSideProps, no getStaticProps, no generateStaticParams, no decision about which rendering strategy a page should use. Every component is a regular React component. Every route is a regular React Router route. The mental load is dramatically lower, and that frees energy for actual product work.
Flexibility. A Vite build produces a folder of static files. I can deploy it to Lovable, Netlify, Vercel, Cloudflare Pages, Render, an S3 bucket with CloudFront, or even a cheap shared host. There is no Node.js server to keep alive, no cold start penalty, no "edge runtime" gotchas. For client projects, this matters because the client owns the hosting after handoff and I want their bill to be ten dollars a month, not two hundred.
Bundle size. A typical Vite + React app I ship is between 100 and 180 KB of JavaScript, gzipped, including the framework. A similar Next.js App Router app starts at around 200 KB before you've written a line of business code. On a mobile connection in Damascus or Khartoum, that gap is the difference between an app that feels instant and one that feels sluggish for the first three seconds.
Honest dev experience. Hot Module Reload in Vite is essentially perfect - state preserves, edits show up in under 100 milliseconds, and I almost never need to restart the dev server. Next.js has improved a lot here, but it's still noticeably slower and occasionally requires a full restart when something gets confused.
I don't think Next.js is wrong. I think it's a great tool that's being used for the wrong job most of the time. The cases where I still reach for it:
If any of those apply, Next.js is the better answer. If none of them apply, Vite is almost certainly the better answer.
This stack covers about 90% of my client work. It is fast to develop in, fast to build, fast to deploy, and - most importantly - easy to hand off to whoever picks up the project next. I've handed off three Vite projects to junior developers and all three were productive within a week.
Here's what a typical "fetch and render" looks like in both stacks. In Next.js App Router:
// app/projects/page.tsx
import { db } from '@/lib/db';
export default async function ProjectsPage() {
const projects = await db.project.findMany();
return <ProjectsList projects={projects} />;
}
This is elegant on the surface, but you've now committed to running a Node process, you've coupled your component tree to a server runtime, and you've added a layer where "this is a server component" vs "this is a client component" becomes a thing you have to think about constantly.
In Vite + React + TanStack Query:
// src/pages/Projects.tsx
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
export default function ProjectsPage() {
const { data: projects } = useQuery({
queryKey: ['projects'],
queryFn: async () => {
const { data } = await supabase.from('projects').select('*');
return data;
},
});
return <ProjectsList projects={projects ?? []} />;
}
Slightly more verbose, but everything happens in the browser, every component is the same kind of component, deploys are static files, and the caching/refetching behavior is explicit instead of magical.
I'm not going to pretend this is free. Switching to Vite costs you:
next/image. I usually pre-process images at build time with a script, or use Cloudinary for client uploads.React.lazy and Suspense yourself instead of getting it for free. It's about thirty extra lines of code, total.For 90% of the projects I work on, these trade-offs are net positive. For the other 10%, I just use Next.js.
Ask one question: does my first paint need to be HTML with content?
If yes - Next.js (or Remix, or Astro). The SSR cost is paying for a real benefit.
If no - Vite + React. You get a faster dev loop, smaller bundles, cheaper hosting, and a simpler mental model.
That's the whole decision. Everything else - file routing, image optimization, middleware - is a feature you can add to either stack if you actually need it.
The temptation in our industry is to pick the most powerful tool because someday you might need its full power. The reality is most projects never reach "someday." They reach a launch date, they reach a handoff, they reach a sunset.
The best tool is the simplest one that solves the problem in front of you. For most SPAs, that's Vite + React, and I'm not going back.