Why Developers Hate JavaScript Frameworks

by Daniel Reeves
Why Developers Hate JavaScript Frameworks

Every few years, the JavaScript ecosystem hands you a new framework and tells you this one is different. This one is fast, minimal, opinionated in just the right ways. You migrate. You rewrite. You attend the conference talk. Then, eighteen months later, the GitHub repo goes quiet and the Discord server starts filling up with "is this project still maintained?" threads.

This is not bad luck. It's the structure of the thing.

Why developers hate JavaScript frameworks is a question that gets asked ironically on Twitter and seriously in engineering retrospectives. Both audiences deserve a straight answer. It's not that the frameworks are universally bad — some are genuinely impressive pieces of engineering. It's that the relationship between developers and frameworks has a predictable failure mode, and the industry keeps repeating it.

The Churn Is Real, and It Has a Cost

Let's put some numbers on this. React was released in 2013. Angular (the rewrite of AngularJS) landed in 2016. Vue 3 shipped in September 2020 with a Composition API that broke enough patterns that entire teams delayed migration for a year. Svelte 4 came out in June 2023. SvelteKit went stable in December 2022. Solid.js has been gaining traction since 2021. Qwik hit 1.0 in May 2023.

That's a lot of "stable" releases in a short window. Each one comes with a migration guide, a new mental model, and an implicit message: what you knew before was fine, but this is better.

For a solo developer working on side projects, that's exciting. For a team maintaining a production app with 200,000 lines of TypeScript, it's exhausting. The hidden cost isn't the migration itself — it's the three months of reduced velocity while everyone gets up to speed, the tribal knowledge that walks out the door when the one person who understood the old patterns leaves, and the resume-driven development that pulls engineers toward the new thing regardless of whether the old thing was actually broken.

I've sat in planning meetings where the primary argument for adopting a new framework was "it'll help with hiring." That's a real concern. It's also a sign that something is wrong with how the ecosystem is structured.

Abstraction Debt Nobody Talks About

Here's the thing about abstractions: they save you time right up until they don't, and when they stop saving you time, they start costing you more time than the underlying problem ever would have.

React's useEffect is the canonical example. The hook was introduced to replace lifecycle methods and make side effects more composable. In simple cases, it works. In real cases — where you're dealing with stale closures, dependency arrays that lie, and effects that run twice in Strict Mode (intentionally, since React 18) — you end up spending hours debugging behavior that has nothing to do with your actual product problem.

Consider this minimal example of the classic stale closure trap:

function Counter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    const id = setInterval(() => {
      // 'count' is stale here — always reads 0
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []); // empty deps: runs once, captures stale count

  return <div>{count}</div>;
}

The fix — using the functional updater form setCount(c => c + 1) or adding count to the dependency array — is well-documented. But the fact that this trap exists at all, that it bites intermediate developers regularly, and that the framework's own linting rules (eslint-plugin-react-hooks) sometimes give you conflicting signals about how to resolve it... that's abstraction debt. You're paying interest on a design decision you didn't make.

Angular has its own version of this with Zone.js and change detection. Vue 3's reactivity system is genuinely elegant, but the mental overhead of knowing when to use ref versus reactive, and why .value is required in one context but not another, trips up developers who are otherwise competent engineers.

The Framework Assumes Your Problem

Most JavaScript frameworks are designed around a specific problem shape: a single-page application with client-side routing, a component tree, and a state management story. That problem shape covers a lot of ground. It doesn't cover everything.

If you're building a content-heavy site that needs to rank in search, you're fighting the SPA model from day one. The frameworks have answers — Next.js for React, Nuxt for Vue, SvelteKit for Svelte — but now you're not just learning a framework, you're learning a meta-framework, and the meta-framework has its own abstractions, its own deployment assumptions, and its own breaking changes. Next.js 13's App Router, released in October 2022 and pushed as stable in Next.js 13.4 in May 2023, introduced a new file-based routing paradigm that invalidated a significant chunk of existing tutorials and documentation. Developers who had invested in the Pages Router found themselves holding knowledge that was technically still supported but clearly deprioritized.

This pattern — where the framework evolves faster than your team's ability to absorb the changes — is one of the core reasons why developers hate JavaScript frameworks. It's not irrational frustration. It's a reasonable response to a recurring experience.

The Marketing-to-Reality Gap

Every framework ships with benchmarks. Usually those benchmarks measure something real: time-to-interactive on a synthetic page, bundle size for a todo app, hydration speed on a controlled test. The numbers are accurate. The context is missing.

Qwik's resumability story is genuinely interesting — the idea that you don't hydrate at all, you serialize execution state and resume it on the client, is a real architectural innovation. But the "zero hydration" marketing collides with the reality that most apps have dynamic content that still needs JavaScript to run, and the programming model (with its $ suffixes and serialization constraints) has a learning curve that the landing page doesn't fully communicate.

I'm not saying these frameworks are dishonest. I'm saying there's a consistent gap between what the benchmark shows and what the production experience feels like, and developers who've been burned by that gap a few times develop a healthy skepticism that can look like hatred from the outside.

When the Vanilla Option Is Actually Correct

Sometimes the right answer is to not use a framework at all. I know that sounds like a contrarian position, but hear me out.

For a marketing site with three interactive components, the overhead of a full React setup — Webpack or Vite config, JSX transform, component hydration, state management decisions — is not justified. A few hundred lines of vanilla JavaScript, or a lightweight library like Alpine.js (which weighs around 15kB minified and gzipped), will do the job with less surface area to maintain.

The web platform itself has gotten significantly better. Custom elements, the CSS :has() selector, the View Transitions API, dialog as a native HTML element — these are real capabilities that didn't exist or weren't widely supported five years ago. The argument for frameworks has always been partly "the platform doesn't do this yet." That argument is weaker now than it was in 2015.

This doesn't mean frameworks are obsolete. A complex application with shared state, dozens of routes, and a team of ten engineers absolutely benefits from the conventions a framework provides. But the default answer shouldn't always be "reach for a framework." The fact that it often is — partly because of hiring concerns, partly because of ecosystem inertia — is worth examining.

The Honest Takeaway

Why developers hate JavaScript frameworks usually comes down to three things: the churn wears them down, the abstractions eventually betray them, and the marketing sets expectations the reality can't meet. None of that is unique to JavaScript — every ecosystem has versions of this problem — but JavaScript's pace and the sheer volume of options makes it more acute here than almost anywhere else.

The frameworks aren't going away. React will still be the default answer on most job postings in 2025. That's fine. But going in with clear eyes about the tradeoffs — understanding that you're not just choosing a tool, you're choosing a dependency on someone else's architectural decisions, roadmap, and funding situation — makes you a better engineer than the one who just follows the hype cycle.

Tomorrow, before you start that new project: ask whether you actually need a framework, or whether you need what you've been told a framework provides. Those are different questions, and the second one has a better answer.