No, You Don't Need Next.js
I've worked at four companies in the last six years. At three of them, someone pushed for adopting Next.js. At two of them, we did. At one of them, it was the right call. At the other, we spent eighteen months unwinding the decision.
This isn't a post about Next.js being bad. It's a post about the industry's pathological need to adopt whatever framework is trending on Twitter, and the specific ways Next.js has become the poster child for this dysfunction.
The Pitch Meeting
You've heard it. I've heard it. We've all sat in that meeting.
"Next.js gives us SSR out of the box. It has file-based routing. Vercel handles deployment. It's what everyone's using now."
What they don't say:
- "I want to put this on my resume"
- "I'm bored with our current stack"
- "I watched a YouTube tutorial and it looked cool"
- "I don't actually understand how SSR works but this makes it easy"
The pitch is always about developer experience and features. It's never about whether the project actually needs those features, or what we're giving up to get them.
You Probably Don't Need SSR
Let me be real: most applications don't need server-side rendering.
SSR makes sense when:
- SEO is critical (marketing sites, blogs, e-commerce product pages)
- First contentful paint matters for business metrics
- You're serving content that changes per-request and can't be statically generated
SSR doesn't make sense when:
- You're building an internal dashboard
- You're building a SaaS app behind a login
- Your content is user-specific anyway
- You're building a CRUD app
That internal admin panel your company is building? It doesn't need SSR. Nobody is Googling for your internal inventory management system. The extra complexity buys you nothing.
But I've watched teams adopt Next.js for internal tools because "it's what we use for the marketing site" or "it's what everyone knows." Then they spend months fighting with the framework because their use case doesn't match what it's optimized for.
The Vendor Lock-In Nobody Talks About
Here's the dirty secret: Next.js is a product designed to drive Vercel revenue.
This isn't a conspiracy theory. It's a business model. Vercel employs the Next.js team. They design features that work best on Vercel's platform. They deprecate features that don't align with their hosting model.
Let's look at the progression:
Next.js 9 (2019): API routes introduced. Works anywhere Node runs.
Next.js 12 (2021): Middleware introduced. Initially worked anywhere. Then restricted to Edge runtime. Which Vercel happens to sell.
Next.js 13 (2022): App Router introduced. Server Components. Aggressive caching that works great on Vercel's infrastructure. Works... differently elsewhere.
Next.js 14-15: Partial Prerendering. More features tied to specific deployment patterns that Vercel optimizes for.
Try running a Next.js 14+ app with all features on AWS Lambda. Try it on a traditional VPS. Try it on Cloudflare. You'll find rough edges everywhere. Features that "just work" on Vercel require workarounds elsewhere.
This is by design. It's not malicious - it's business. But you should understand what you're signing up for.
"Just Deploy to Vercel"
I've heard this response to every complaint about Next.js deployment complexity:
"Just deploy to Vercel, it's easy."
Cool. Let's talk about what "just deploy to Vercel" means for a real company:
- You're now paying Vercel's pricing, which gets expensive fast at scale
- Your infrastructure is now split between Vercel and whatever else you're using
- Your CI/CD pipeline now has a Vercel-specific path
- Your ops team needs to learn Vercel's platform
- Your security team needs to audit another vendor
- Your compliance requirements now include another third party
For a startup or small project, fine. For an established company with existing infrastructure, "just use Vercel" is a massive decision being presented as a simple one.
And what happens when Vercel raises prices? Changes terms? Gets acquired? Goes down? You're locked in. Migrating away from Next.js at that point means rewriting your application.
You Can Build SSR Yourself
Here's something the framework maximalists don't want you to know: SSR is not complicated.
Here's a basic SSR setup with Express and React:
import express from 'express';
import { renderToString } from 'react-dom/server';
import App from './App';
const app = express();
app.get('*', (req, res) => {
const html = renderToString(<App url={req.url} />);
res.send(`
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
<div id="root">${html}</div>
<script src="/client.js"></script>
</body>
</html>
`);
});
app.listen(3000);That's it. That's SSR. Yes, you need to handle data fetching. Yes, you need to handle hydration. Yes, there's more work to make it production-ready. But the core concept is simple.
What Next.js gives you:
- File-based routing
- Automatic code splitting
- Built-in data fetching patterns
- Image optimization
- A bunch of other conveniences
What Next.js costs you:
- Framework lock-in
- Vercel-optimized architecture
- Complexity you may not need
- Upgrade pain every major version
- Black-box behavior when things go wrong
For many projects, writing your own thin SSR layer gives you exactly what you need without the baggage. You understand every line of code. You can deploy anywhere. You're not on someone else's upgrade treadmill.
The Upgrade Treadmill
Speaking of upgrades, let's talk about Next.js's versioning.
Next.js 13 introduced the App Router, a fundamental reimagining of how Next.js applications work. It deprecated (but didn't remove) the Pages Router that everyone had been using.
If you were on Next.js 12, you had a choice:
- Stay on the old architecture and miss new features
- Rewrite significant portions of your application for the new architecture
- Run both architectures in parallel during a multi-month migration
I watched a team spend six months migrating from Pages Router to App Router. Six months of engineering time. For what? So they could use Server Components that they then had to be very careful about because of security issues like CVE-2025-55182.
This isn't a one-time thing. It's the pattern. Next.js moves fast because Vercel needs to ship features to stay competitive. You're along for the ride whether you want to be or not.
The Real Cost of "Developer Experience"
The Next.js pitch is always about developer experience. Fast refresh. Easy routing. Simple deployments.
But developer experience isn't free. It's purchased with:
Abstraction complexity: When things work, great. When they don't, you're debugging through layers of framework code you don't understand. The error messages assume you understand the mental model. If you don't, you're lost.
Build time: Next.js builds are slow. Every project I've worked on has had complaints about build times. The framework does a lot of work, and that work takes time.
Bundle size: Next.js adds weight. The runtime isn't free. For projects where bundle size matters, you're fighting the framework.
Mental model lock-in: Once your team thinks in Next.js patterns, they struggle to work outside them. "How do I do X in Next.js?" becomes the question, not "How do I solve this problem?"
When Next.js Actually Makes Sense
I'm not saying never use Next.js. I'm saying think before you adopt it.
Next.js is a reasonable choice when:
- You're building a marketing site or content-heavy application where SEO matters
- You're a small team that will actually benefit from Vercel's managed infrastructure
- Your use case aligns with Next.js's optimizations
- You've evaluated the lock-in tradeoffs and decided they're acceptable
- You actually need the features it provides
Next.js is a poor choice when:
- You're building an internal tool or dashboard
- You're a larger company with existing infrastructure investments
- You're building a SPA that doesn't need SSR
- You value long-term flexibility over short-term convenience
- Your team doesn't actually understand what the framework is doing
The Cargo Cult Problem
The deeper issue isn't Next.js specifically. It's the cargo cult adoption of whatever framework is currently popular.
Every few years, we get a new "right way" to build web applications:
- 2015: "Just use React"
- 2018: "Just use Gatsby"
- 2020: "Just use Next.js"
- 2023: "Just use the App Router"
- 2025: "Just use Server Components"
Each wave brings people who adopt the new thing because it's the new thing, not because they've evaluated whether it's right for their specific situation.
The result is a trail of abandoned migrations, half-upgraded codebases, and teams who can't explain why they made the choices they made.
Make Boring Choices
Here's my advice: make boring choices.
- If a plain React SPA works for your use case, use that
- If you need SSR, consider whether a simple custom setup would suffice
- If you adopt a framework, understand exactly what you're trading for the convenience
- Don't adopt technology because it's trending
- Don't let "everyone's using it" substitute for actual analysis
The best technology choice is usually the one that does exactly what you need and nothing more. Complexity has costs. Abstractions have costs. Dependencies have costs.
Next.js might be the right choice for your project. But if you can't articulate specifically why, beyond "it's what everyone uses," you're cargo-culting. And cargo-culting has consequences.
Usually around eighteen months later, when someone's writing a document titled "Next.js Migration Retrospective" and trying to explain to leadership why the team needs another six months.
The Bottom Line
Stop pushing Next.js on every project. Stop letting "developer experience" trump actual requirements analysis. Stop adopting frameworks because they're trending.
Think about what you actually need. Evaluate the tradeoffs honestly. Make a deliberate choice based on your specific situation.
And maybe, just maybe, consider that the boring choice - the plain React app, the simple Express server, the technology you already understand - might be the right one.
The new shiny thing isn't always better. Sometimes it's just shinier.