Next.js: The Good, The Bad, and The 'Why Is This So Complicated?'
An honest take on Next.js after building real projects - what works, what doesn't, and when to consider alternatives
Next.js: The Good, The Bad, and The 'Why Is This So Complicated?'
🤔 What Even Is Next.js?
Is it a framework? A meta-framework? A React wrapper? A full-stack framework? Yes.
Next.js is React on steroids - it takes React (which handles UI) and adds routing, server-side rendering, API routes, image optimization, and a bunch of other stuff that you'd otherwise have to configure yourself.
Simple version: React makes it easy to build UIs. Next.js makes it easy to ship those UIs to production with good performance and SEO.
✅ What Next.js Actually Solves
1. Routing Without the Pain
React alone:
npm install react-router-dom
# Configure routes manually
# Set up lazy loading
# Handle 404s
# Deal with nested routes
# Cry
Next.js:
# Create /app/about/page.tsx
# That's it. You have a /about route.
File-based routing is genius. The file structure IS the routing structure. No configuration. No imports. Just works.
2. Server-Side Rendering (SSR) for Free
Problem with React SPA:
- Google crawls your site: sees empty
<div id="root"></div> - User loads page: stares at blank screen while JS downloads
- SEO: Dead
- Performance: Terrible
Next.js:
// This runs on the server
export default async function Page() {
const data = await getData() // Fetch before HTML sent
return <div>{data}</div> // HTML already has content
}
User gets fully rendered HTML instantly. Search engines see real content. Everyone wins.
3. Image Optimization Built-In
Regular img tag:
<img src="/huge-photo.jpg" />
<!-- 5MB image loads -->
<!-- User on slow connection: 😢 -->
<!-- Lighthouse score: 💀 -->
Next.js Image:
<Image src="/huge-photo.jpg" width={800} height={600} />
// Automatically:
// - Resizes to screen size
// - Serves WebP
// - Lazy loads
// - Responsive srcset
// Lighthouse score: 🎉
4. API Routes Without Separate Backend
// app/api/users/route.ts
export async function GET() {
const users = await db.users.findMany()
return Response.json(users)
}
// Now you have /api/users endpoint
// No Express setup
// No separate server
// Just works
Perfect for small projects. Don't need separate backend until you really scale.
5. Code Splitting Automatically
React loads all JavaScript upfront. Next.js only loads what the page needs. Huge performance win.
🎯 Real-World Wins in My Projects
Four-Points (Hotel Management)
- SSR for dashboards: Data-heavy pages load fast
- API routes: Simple CRUD operations without Express
- File routing: Easy to organize 50+ pages
- Image optimization: Hotel photos load instantly
E-commerce Platform
- Product pages: SEO-friendly, pre-rendered
- Performance: 90+ Lighthouse score
- Dynamic imports: Only load checkout code on checkout page
Portfolio (stackbp.es)
- Static generation: Blazing fast
- MDX support: Blog with React components
- Image optimization: Professional photos load fast
💀 Where Next.js Hurts
Let me be honest - Next.js isn't perfect. Sometimes it's frustrating. Here's what sucks:
1. The Version Chaos
Next.js 12 → Different from Next.js 13 → COMPLETELY different from Next.js 14.
Pages Router vs App Router is confusing:
- Old tutorials use Pages Router
- New docs push App Router
- They work differently
- Can't mix them cleanly
- Stack Overflow answers are outdated
Had to relearn routing twice. Documentation for old versions still ranks high in Google. Waste hours debugging until you realize the solution is for Next.js 12 and you're on 14.
2. Server Components Are Confusing
// This is a Server Component (default in App Router)
async function Page() {
const data = await getData() // Works
const [state, setState] = useState() // ❌ ERROR
useEffect(() => {}) // ❌ ERROR
onClick={() => {}} // ❌ ERROR
}
// Want client features? Add this:
'use client'
// Now it works but loses server benefits
// Which components should be server?
// Which should be client?
// Nobody knows. Guess and pray.
The mental model is hard. You have to constantly think "is this running on server or client?" Mix them wrong and weird bugs appear.
3. Over-Engineering for Simple Projects
Building a simple landing page? Next.js might be overkill:
- Node.js server required (can't just open index.html)
- Build step needed
- Environment variables
- Configuration
- Deployment complexity
For a 3-page static site, this is absurd.
4. The Bundle Size Problem
Next.js includes React, which is 40KB+ gzipped. For tiny projects, that's huge overhead.
Simple vanilla JS site: 5KB
Same site in Next.js: 80KB+
Is the DX worth 75KB extra? Sometimes yes. Sometimes no.
5. Deployment Lock-In (Sort Of)
Next.js works best on Vercel (the company that makes Next.js). Surprise!
Deploying to Vercel: One click. Perfect.
Deploying anywhere else:
- Need Node.js server
- Configure build properly
- Handle environment variables
- Set up caching
- Deal with serverless adapters
Not impossible, but Vercel makes it so easy that you feel locked in.
6. The Cache Confusion
Next.js caches EVERYTHING. Sometimes too aggressively:
// Why isn't my data updating?
const data = await getData()
// Oh right, it's cached
const data = await getData({ cache: 'no-store' })
// Wait, revalidate instead?
const data = await getData({ next: { revalidate: 60 } })
// Or use a different fetch approach?
// Who knows anymore
Cache is great for performance, terrible for understanding WTF is happening.
7. Error Messages from Hell
Error: useContext is not a function
Error: Hydration failed
Error: Expected server HTML to contain matching <div>
These errors tell you nothing useful. Google them? 47 different possible causes. Good luck debugging.
🔄 When to Use Next.js (and When Not To)
✅ Use Next.js When:
1. SEO Matters
- Marketing sites
- E-commerce
- Blogs
- SaaS landing pages
2. You Need SSR
- Dashboard with user data
- Dynamic content that should load fast
- Personalized pages
3. Building Full-Stack App
- API routes for backend
- Database integration
- Authentication flows
4. Image-Heavy Site
- Portfolio
- E-commerce with products
- Photo galleries
5. You Want Great DX
- TypeScript support is excellent
- File-based routing is intuitive
- Hot reload is fast
- Dev tools are solid
❌ Don't Use Next.js When:
1. Simple Static Site
- Personal blog with 5 posts
- Company landing page
- Documentation site
→ Use Astro instead: Faster, simpler, better for static content
2. Highly Interactive SPA
- Admin dashboard with no SEO needs
- Internal tools
- Complex state management
→ Use Vite + React: Simpler, faster dev, no SSR overhead
3. Mobile App
- React Native exists
- Next.js on mobile is weird
→ Use React Native or Expo
4. Real-Time Heavy
- Chat applications
- Collaborative tools
- WebSocket-heavy apps
→ Use raw React + Socket.io, or consider other frameworks
5. Bundle Size Critical
- Embedded widgets
- Third-party scripts
- Maximum performance needed
→ Use Preact, Svelte, or vanilla JS
🆚 Alternatives and When They're Better
Astro
When: Static content focus, blog, docs
Why: Faster, ships zero JS by default, easier to learn
Downside: Less dynamic capabilities
Remix
When: Complex data fetching, nested routes
Why: Better form handling, simpler mental model than Next.js App Router
Downside: Smaller ecosystem
Vite + React
When: SPA with no SSR needs
Why: Simpler, faster dev server, no server-side complexity
Downside: No built-in SSR or routing
SvelteKit
When: Want smaller bundles, cleaner syntax
Why: Less JavaScript shipped, simpler reactivity
Downside: Smaller community than React
Nuxt (Vue)
When: You prefer Vue over React
Why: Similar to Next.js but for Vue ecosystem
Downside: Vue ecosystem smaller than React
💡 Lessons from Building with Next.js
1. Start Simple, Add Complexity When Needed
Don't use Server Components everywhere because they're "the new thing". Use them where they help. Use Client Components when you need interactivity.
2. Understand the Trade-offs
SSR is great for SEO, bad for complexity. Static generation is fast, bad for dynamic data. Choose based on your needs.
3. The Docs Are Your Friend (Sometimes)
Next.js docs are actually good. But outdated Stack Overflow answers will mislead you. Always check the version.
4. Vercel Deployment is a Drug
Once you experience one-click deployment, you can't go back. Factor this into your decision.
5. Don't Fight the Framework
If Next.js makes something hard, maybe you're using the wrong tool. Don't force it.
📊 My Personal Take
For Four-Points: Next.js was the right choice. SSR for dashboards, API routes for simple endpoints, image optimization for hotel photos. Works great.
For this portfolio: Next.js is perfect. Static generation, MDX for blog, easy deployment. Love it.
For a simple landing page: I'd use Astro. Next.js is overkill.
For a chat app: I'd use Vite + React + Socket.io. Next.js SSR doesn't help here.
🎯 The Honest Truth
Next.js is incredible when you need what it offers:
- SEO
- SSR
- Image optimization
- File-based routing
- Full-stack capability
But it's also:
- Complex
- Sometimes over-engineered
- Version chaos
- Vercel-optimized (not always portable)
Use it when it solves your problems. Don't use it because it's trendy.
🚀 Final Verdict
Next.js is like a Swiss Army knife:
- Has tools for everything
- Complicated when you need something simple
- Perfect when you need the specific tools it offers
My framework selection process:
- Is it static content? → Astro
- Need SEO + dynamic? → Next.js
- SPA with no SEO? → Vite + React
- Maximum simplicity? → Vanilla JS
- Not sure? → Next.js is a safe bet
Don't cargo cult. Choose based on project needs. But also don't overthink - Next.js is good enough for 80% of projects.
Keep shipping. Choose wisely. 🚀
P.S.: The real secret? The best framework is the one you actually ship with. A finished project in Next.js beats a perfect project that never launches.