Library / SDK
welldone-software/why-did-you-render avatar
welldone-software/why-did-you-render

@welldone-software/why-did-you-render: React 19 re-render tracking via a Babel importSource swap

why-did-you-render by Welldone Software monkey patches React to notify you about potentially avoidable re-renders. (Works with React Native as well.)

12,523 stars224 forksJavaScriptMIT

At a glance

What is it?
why-did-you-render monkey patches React to report re-renders that could have been avoided, and version 10 is the line that supports React 19. The setup is a Babel change plus one file imported first, and the README is explicit that this is a development-only tool.
Who is it for?
Adopt it if you are on React 19 or React Native and want a console-level explanation of why a memo component re-rendered, and you are willing to change your Babel config to make it work. Do not adopt it if you are running React Compiler, if you need React 18 or 16 support (those live on the version 8 and version 7 branches), or if you want a profiler that measures cost rather than reports causes.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 168 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The re-render you cannot explain from the diff

The problem this addresses is narrow and specific. A memo component re-renders, you look at the props, nothing appears to have changed, and you have no way to see which prop failed the shallow comparison or which hook returned a new value. why-did-you-render exists to answer that question in the console. The README's own example is an inline object: passing style={{width: '100%'}} to a big memo component creates a new object on every render of the parent, so the memo comparison fails every time.

The audience is React developers who already suspect a component is re-rendering too often and want the reason rather than a flame graph. It is not a general performance tool. The README warns that not all re-renders are bad, and that reducing them can hurt performance or have a negligible effect, in which case the effort is wasted and the code gets more complicated. It points at the React DevTools Profiler for measuring the effect of any change. That framing is honest and it sets the boundary of the tool: it tells you why, not how much.

How the monkey patch gets between you and React

The mechanism is an import swap, not a runtime hook. In React 19 the automatic JSX transform imports its runtime from a configurable source, and the README instructs you to point that source at @welldone-software/why-did-you-render. The package ships jsx-runtime.js, jsx-dev-runtime.js and matching .d.ts files, which is why the importSource can resolve to it. Once the JSX runtime comes from this package, the library can wrap React and observe component updates.

Two tracking modes follow from that. With trackAllPureComponents, every React.PureComponent and React.memo component is tracked. Otherwise you opt in per component by setting Component.whyDidYouRender = true. Custom hooks can be tracked too through trackExtraHooks, and the README's example is React Redux's useSelector, which it requires alongside the main package inside the same development-only block.

The library is installed as a devDependency, and the README states the library should never be used in production, for two stated reasons: it significantly slows down React, and monkey patching React can result in unexpected behavior. Treat that as a hard constraint on where this code is allowed to run.

Install and first tracked render

Install it as a dev dependency. The README gives both package managers:

bash
npm install @welldone-software/why-did-you-render --save-dev

or

bash
yarn add @welldone-software/why-did-you-render -D

Then change your Babel React preset so the JSX runtime resolves to this package and runs in development mode. This is the step that makes React 19 work, because React 19 requires the automatic JSX transformation:

js
['@babel/preset-react', {
  runtime: 'automatic',
  development: process.env.NODE_ENV === 'development',
  importSource: '@welldone-software/why-did-you-render',
}]

Create a wdyr.js file and import it as the very first import in your application. Under trackAllPureComponents every pure component is tracked, so you do not have to annotate anything to see output:

jsx
import React from 'react';

if (process.env.NODE_ENV === 'development') {
  const whyDidYouRender = require('@welldone-software/why-did-you-render');
  whyDidYouRender(React, {
    trackAllPureComponents: true,
  });
}

In index.js, the import order matters and the README places it before react-hot-loader as well:

jsx
import './wdyr'; // <--- first import

import 'react-hot-loader';

For TypeScript, rename the file to wdyr.ts and add a triple-slash reference to the package types at the top of the file. If nothing appears in the console, the README directs you to its troubleshooting section and to the issue tracker rather than offering a diagnostic command. For React Native there are two separate paths: a bare workflow that adds @babel/plugin-transform-react-jsx inside a development env block in babel.config.js, and Expo managed, where the jsxImportSource is passed through babel-preset-expo.

React Compiler is the wall, and the version ladder is the other one

The clearest limitation is stated by the maintainer in the README itself: the library was not tested with React Compiler at all, and the belief is that it is completely incompatible with it. If your build runs the compiler, this tool is not a candidate. That is not a caveat buried in an issue, it is a caution block at the top of the documentation.

The second limitation is version support. The README states the latest version was tested with React 19 only, and sends React 18 users to the version 8 readme and React 17 and 16 users to the version 7 readme. Those are separate branches, so a project on an older React is not installing the same code with a flag, it is reading different documentation. Anyone on React 18 should expect the v10 setup steps above not to apply.

There is also the production ban, which is a design constraint rather than a bug. Because the library patches React and slows it down, the wdyr file is wrapped in a development check in every example. A team that ships it by accident has changed the behavior of React in production, which is exactly what the README says not to do. And the tool reports causes, not costs: the README's own advice is to focus on heavier components and use the React DevTools Profiler to measure whether a change helped.

Against a profiler, and against the React Compiler

The natural alternative is the React DevTools Profiler, which the README itself recommends for measuring the effects of changes. The difference in approach is real. The profiler records commit durations and render counts and shows you where time went; it answers how expensive a render was. why-did-you-render answers why a render happened at all, naming the prop or hook value that broke the memo comparison. A team optimizing a slow list wants the first; a team staring at a memo component that re-renders for no visible reason wants the second. They are complements, and the README treats them that way.

The other alternative is the React Compiler, which takes the opposite position entirely: instead of reporting avoidable re-renders for a human to fix, it memoizes automatically at build time. That removes the class of problem this library reports. It also means the two cannot coexist here, per the README's incompatibility note. Choosing the compiler is choosing to stop hand-tuning memo boundaries, and choosing why-did-you-render is choosing to keep inspecting them.

Who should wire this into their Babel config

Use it if you are on React 19 or React Native, you have a specific component that re-renders more than you expect, and you want the console to name the prop or hook responsible. The setup cost is one Babel preset change and one file imported first, and the payoff is immediate on the first tracked render. Use trackAllPureComponents to survey, then narrow to per-component opt-in once you know which components matter.

Do not use it if you run React Compiler, if you are pinned to React 18 or below and do not want to follow an older branch's readme, or if your question is about total render cost rather than render cause. It is also the wrong tool for a production build under any circumstance, and the README says so directly.

Before adopting, verify two things in your own repository. First, that your bundler and Babel setup actually resolve the JSX runtime from the importSource you configure, since the whole mechanism depends on it. Second, that wdyr.js is the first import in your entry file, ahead of react-hot-loader and anything else that touches React. If logs do not appear, the README points to its troubleshooting section rather than to a diagnostic flag.

Licence, release cadence and what an upgrade costs

The package is MIT licensed, published as @welldone-software/why-did-you-render on npm, with types.d.ts as the declared types entry and dist/whyDidYouRender.js as the main entry. MIT is permissive, but the README's production warning is a usage constraint the licence does not override, and none of this is legal advice.

The release history is uneven rather than steady. v10.0.0, titled for React 19 support, landed on 2025-01-18, followed by v10.0.1 the same day. Before that, v8.0.3 was released on 2024-06-08. The last push to the repository was on 2026-04-15, so the project has seen activity in 2026 even though the newest tagged release is from January 2025. Upgrades are not free: the README's version ladder means a React major bump can move you to a different readme and a different setup, and the React Compiler note means a build-tooling change can invalidate the tool entirely. Budget for re-reading the setup section, not for a drop-in version bump.

Editorial conclusion

Adopt it if you are on React 19 or React Native and want a console-level explanation of why a memo component re-rendered, and you are willing to change your Babel config to make it work. Do not adopt it if you are running React Compiler, if you need React 18 or 16 support (those live on the version 8 and version 7 branches), or if you want a profiler that measures cost rather than reports causes. Verify first that your bundler reads the JSX runtime from the importSource you set, and that wdyr.js is the first import in your entry file.

Frequently asked questions

How do I use @welldone-software/why-did-you-render in a React 19 app?

Install it as a dev dependency, set importSource to @welldone-software/why-did-you-render in @babel/preset-react with runtime automatic and development mode on, then create wdyr.js and import it as the very first import in your application.

Why did you render in a Next.js project: does this library support it?

The README documents setup for plain React, Create React App, and React Native through Babel config, but it does not give Next.js specific instructions, so the importSource and first-import steps would have to be mapped onto Next.js's Babel configuration by the reader.

What is the alternative to why-did-you-render?

The README itself points to the React DevTools Profiler for measuring the effects of changes, and the React Compiler takes a different approach by memoizing automatically. The README states the library was not tested with React Compiler and is believed to be completely incompatible with it.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. welldone-software/why-did-you-render on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/welldone-software-why-did-you-render.svg)](https://hysenlabs.com/projects/welldone-software-why-did-you-render)