Hiprup

What are the limitations of Next.js?

Next.js is a strong default for most React apps, but it has trade-offs worth knowing before you commit.

  • Framework lock-in — moving off Next.js later is non-trivial. File-based routing, Server Components, Server Actions, and the caching model all tie you to the framework. Plain React or Vite apps are easier to migrate.

  • Steep learning curve in the App Router — Server vs Client Components, the caching layers, streaming with Suspense, Server Actions, async params — there's a lot to internalize before you're productive. The mental model is different from vanilla React.

  • Caching complexity — the Full Route Cache, Router Cache, Data Cache, and request memoization interact in subtle ways. Stale content and cache-invalidation bugs are a common source of production surprises.

  • Build times on large sites — projects with thousands of static pages can take minutes to build. ISR and on-demand revalidation help, but cold builds still grow with page count.

  • Self-hosting friction — Vercel is frictionless, but matching feature parity on your own infrastructure (ISR, image optimization, middleware, edge functions) requires work. Not every Next.js feature runs cleanly on every platform.

  • Cold starts on serverless — when deployed as serverless functions, dynamic routes can have noticeable cold-start latency, especially with large dependency graphs. Edge runtime helps but has its own limitations.

  • Edge runtime constraints — middleware and Edge routes run on a V8-isolate runtime, not Node. Many npm packages don't work (anything using Node core modules, native bindings, or large file I/O).

  • Bundle size of the runtime — the Next.js client runtime is heavier than a hand-built React+Vite setup, particularly for small pages where the framework overhead dominates.

  • Rapid breaking changes — the App Router has been evolving fast. Patterns recommended a year ago sometimes shift. Version 15's caching-default inversion was a meaningful migration.

  • Non-trivial Docker images — without output: 'standalone', production images bundle node_modules and can get large. standalone is great but it's an extra config step.

  • Limited SSE and long-lived connections — Server-Sent Events and WebSocket-style long-lived connections don't fit serverless deployments well. You usually need a separate service for them.

  • React-only — if you want Vue, Svelte, or Solid, Next.js isn't for you.

When Next.js is probably the wrong choice:

  • Embedded widgets or component libraries — use Vite library mode or tsup.

  • Pure SPA dashboards behind auth where SEO doesn't matter — Vite+React Router is simpler.

  • Content sites that want minimal JS — Astro ships less JavaScript and is optimized for static content.

  • Real-time-heavy apps — a dedicated Node server (Fastify, NestJS) with WebSocket support may fit better.

For most product apps — landing pages, authenticated UI, some API routes, SEO matters — Next.js is still the path of least resistance despite these tradeoffs.

Be honest about limitations — it shows maturity. Key ones: Vercel-centric features, learning curve, middleware Edge Runtime restrictions.

Balance by mentioning how these tradeoffs are often worth it for the benefits.

What are the limitations of Next.js? | Hiprup