Home / Articles

Retiring Legacy JavaScript Dependencies: CRA, Moment, jQuery and More

Which aging JavaScript libraries and tools to phase out, why each became a liability, what replaces it, and how to keep your dependency list from rotting again.

Publisher: REACTAPP.TOP6 min read1411 words

This article is published in English.

Sources: **JavaScript Libraries and Tools Heading Toward Deprecation: What to Drop in 2026**

Most JavaScript projects carry a few dependencies that were the obvious choice when the repository was created and are now dead weight: large bundles, unpatched vulnerabilities, awkward fits with modern runtimes, or features the platform now provides for free. None of them break overnight, which is exactly why they linger. This guide walks through the libraries and tools that are deprecated, frozen in maintenance mode, or steadily losing ground, explains why each one fell behind, and names the replacement you should reach for so you can plan migrations deliberately instead of under pressure.

Build and scaffolding tools

Create React App

For years Create React App (CRA) was how a React project started. In early 2025 the React team formally deprecated it as a starting point for new apps, and it no longer gets meaningful updates, so security problems in its toolchain stay unresolved. Its download numbers have been falling fast as teams move on.

The underlying reasons are structural: nobody is actively maintaining it, its assumptions about bundling and dev servers are dated, and the alternatives cover modern requirements such as server rendering, faster builds and a better developer experience without extra setup. Good replacements include:

  • Vite with @vitejs/plugin-react for the typical single-page app
  • Next.js, Remix / React Router or another full framework if the app needs a router, data fetching conventions or server-side code
  • Parcel or Rsbuild if you want something lighter

Because a CRA app is mostly standard React code plus a hidden build configuration, the migration tends to be much smaller than teams expect: you swap the build tool, move the HTML entry point and environment variable conventions, and the components themselves stay untouched. If you are starting fresh, the walkthrough in our React and Vite setup guide covers the new baseline.

Webpack for new projects

Webpack is far from dead. A huge number of production applications still build with it, and that will not change soon. What is shrinking is its share of new projects, mainly because of configuration complexity and slower cold starts than newer tools. For greenfield frontend work, Vite is the current default, with Rspack and esbuild-based setups as other strong options. Webpack remains reasonable for very complex existing configurations, but it is rarely where a new project should begin. For a deeper comparison of the options, see choosing a bundler.

Libraries the platform has absorbed

Moment.js

Almost every JavaScript developer has used Moment.js at some point. Its own maintainers have long described it as a legacy project in maintenance mode. It is large, its objects are mutable by default (a common source of bugs when a date is modified in one place and observed in another), and it does not tree-shake well.

Native date handling has improved, and small immutable libraries now do the job with better performance. Your options, roughly in order of preference:

  • Intl.DateTimeFormat for locale-aware formatting
  • Temporal, the new built-in date and time API that developers waited years for, which has been rolling out across runtimes and browsers; check current support for your targets before depending on it
  • date-fns, Luxon or Day.js if a library is still warranted

If Moment is still in your dependency tree, schedule the migration. The bundle-size reduction alone is often substantial.

jQuery

jQuery solved genuine cross-browser pain in the 2010s. For new code today it is almost never justified, since standardized DOM APIs, fetch and component frameworks cover everything it used to smooth over. Plain JavaScript with querySelector, classList, addEventListener and native fetch handles most direct DOM work, and React, Vue, Svelte or Solid take over when you need component-based interfaces. Legacy codebases will keep jQuery alive for years, and that is fine, but reaching for it in a brand-new project is a warning sign.

Lodash and Underscore

Before ES2015, Lodash was close to mandatory. Now most of its helpers have native equivalents: array methods such as map, filter and reduce, Object.entries, optional chaining, nullish coalescing and more. Shipping the whole library, or even large pieces of it, to use a handful of functions is hard to justify. Start with the language itself and add a focused utility only where the native API genuinely falls short, for example deep equality or debouncing. Our article on native features that replace utility dependencies goes through concrete replacements.

Testing and networking

Enzyme

Enzyme was the dominant way to test React components for a long time, but it never adapted well to React 18 and its concurrent features, and adoption has collapsed. Because Enzyme encouraged testing component internals (state, instance methods, shallow render trees), migration is partly a change of mindset. React Testing Library, the option recommended by both the community and the React team, tests what the user sees and does instead. Pair it with Vitest or Jest as the runner.

request and node-fetch v2

request was officially deprecated a long time ago and no longer gets security patches, so any remaining usage is an open risk. node-fetch v2 has also seen its downloads fall sharply because Node.js 18 and later ship a global fetch (it was flagged experimental in the early releases, so confirm the behavior on your Node version). Use native fetch, which now works in modern Node and every current browser. When you need retries, interceptors or more capable streaming, look at undici, ky or got.

Other items worth tracking

A few more changes deserve a place on your upgrade list:

  • ESLint 9.x reached end-of-life in August 2026 according to its release schedule; plan the move to the v10 line and verify the dates on the ESLint site.
  • The AWS SDK for JavaScript v2 is past end-of-support. Switch to the modular v3 clients under @aws-sdk/*, which also lets you import only the clients you use.
  • Older scaffolding such as vue-cli and Nuxt 2 is effectively legacy.
  • Node.js keeps deprecating built-ins and older APIs as the runtime modernizes, so read the official deprecations list before every major-version upgrade.
  • Runtimes such as Bun ship more functionality natively, which further reduces the need for many small utility packages.

A routine that keeps dependencies current

Replacing these libraries once is not enough; the goal is a habit that stops the next generation of stale dependencies from piling up.

  1. Audit package.json on a schedule and run npm outdated and npm audit so drift is visible.
  2. Prefer native platform features once they are stable and broadly supported in the environments you target.
  3. Watch the deprecation announcements published by React, Node.js, ESLint and the maintainers of your major libraries.
  4. Treat "it still works" as a temporary state. Ongoing security patches and ecosystem backing outweigh the convenience of leaving things alone.
  5. Default new projects to modern tooling: Vite, the built-in fetch, Temporal where supported, and current major versions of frameworks.

A useful trade-off to keep in mind: not every legacy dependency deserves an immediate rewrite. A stable internal tool using jQuery or Webpack may cost more to migrate than it will ever save. Prioritize by exposure. Anything unmaintained that touches the network, user input or your build pipeline (request, CRA, AWS SDK v2) comes first; bundle-size wins such as Moment and Lodash come next; purely stylistic modernization can wait.

Key takeaways

  • Deprecated and unmaintained packages are a security problem first and a performance problem second, so rank migrations by risk.
  • Many former staples (Moment, Lodash, jQuery, request) have been absorbed by the language, the DOM or the runtime, which makes the replacement smaller than the dependency.
  • Tooling migrations such as CRA to Vite usually touch configuration, not application code.
  • A regular audit and a default of modern tooling for new work keep the list short in the future.