React and the Community in 2025, Part 2: React Team Interactions with the Community
This is a post in the React and the Community in 2025 series.
Introduction ๐︎
As we start 2025, the state of React and its ecosystem is complicated and fractured, with a mixture of successes, skepticism, and contention.
On the positive side, the React team recently released React 19 after multiple years of development. This was a huge release, including official stable React Server Components support, the new use hook for handling promises, multiple new form integrations, and the removal of many long-deprecated and obsolete features.
However, I've observed and experienced that the React community has had a growing sense of frustrations and disagreements on where React is headed, how it's developed, and the recommended approaches for using React, as well as the interactions between the React team and the community. This in turn overlaps with dozens of different arguments that have ricocheted around the React and general web dev communities in the last few years, as well as specific technical concerns with how React works, comparisons with other similar JS frameworks, and how web apps should be built going forward.
What makes this a lot worse is that everyone is arguing and debating a different subset of these concerns, and many of the stated concerns are either false or outright FUD. Unfortunately, the arguments and fears have also been exacerbated by numerous self-inflicted missteps, communications problems, and lack of developer relations work from the React team itself. All of these intertwine heavily.
I've been involved in many related discussions on social media. I've written numerous comments both defending and critiquing the React team, explaining why they made certain decisions or how things actually happened, pushing for improvements to docs and explanations, and more.
Trying to cover most of these topics has required a post far longer than even I usually write (and I'm not even going to touch on the "is React bad / how does React compare to other tools?" topics, which are even further out of scope). But, having spent far too many hours debating and explaining, I feel the need to write a consolidated post that covers many of these topics together.
In Part 1: Development History and Clarifying Community Concerns, I described the history of React's development process and influences on how it's been developed, looked at how React has historically been used, and clarified common confusions around the React team's motivations and where React is headed.
I strongly encourage readers to read Part 1 first, to understand the background and context for the events described in this post.
Goals ๐︎
My goals for this post are:
- Describe and highlight several areas where I see major disagreements and disconnects between the React team and the rest of the community
- Look at how the React team has historically interacted with the community, point out both good and bad approaches I've seen from the React team, and explain how the friction has often led to community frustrations
- Provide some recommendations on what I'd like to see done to improve the future of communications between the React team and the community, make it easier for beginners to learn React, and improve the health of the React ecosystem
Background: My Role and Involvement in the React Community ๐︎
(aka "who am I, why should you trust my descriptions, and why should you care at all what my opinions are about this? ๐")
I am not and never was part of the actual React team. That said, I've been deeply involved with the React ecosystem since 2015, and it's fair to say I'm as much part of the "React community inner circle" as anyone outside of Meta or Vercel.
As a TL;DR:
- I've used React since 2015
- I maintain the Redux family of libraries, contributed to React, and been involved in React ecosystem discussions
- I've written numerous lengthy tutorials on React and Redux, and frequently speak on React and Redux
- I've been involved in moderating major React community sections most of that time
If you want the long version:
My Accomplishments, Involvement, and Credentials
I started learning React in mid-2015, after using Backbone, jQuery, and GWT to build some geospatial visualization apps. Over the next year, I went from reading a few React tutorials, to lurking in the Reactiflux chat channels, to answering so many questions I became a moderator, to volunteering to write a Redux FAQ, to being handed the keys as the new Redux maintainer.
I've maintained Redux since mid-2016. I created Redux Toolkit as the modern way to write Redux apps. While working on Redux, I've designed and shipped every version of React-Redux since v5. I've had multiple conversations with the React team about how React should work with external state management libraries, and I was the sole alpha-tester for the development of the useSyncExternalStore hook.
I've written hundreds of thousands of words of tutorials and blog posts teaching people how to use React and Redux and how they work, including the "Redux Essentials" tutorial and my widely acclaimed "Guide to React Rendering Behavior" post (which is routinely recommended by the community as the single best explanation of how React actually works in practice). I've written thousands of comments and answered questions across Github, the Reactiflux Discord, Reddit, Twitter, Hacker News, and Stack Overflow, about all things React and Redux and JS. I've been referred to as "the tech support for the React community" and "the master archiver and indexer of all things React".
I've spoken at numerous React-related conferences on topics ranging from how React works to best practices and lessons learned maintaining widely used OSS libraries. I've been on numerous podcasts discussing React and Redux, including the ongoing "This Month in React" podcast hosted by the Reactiflux Discord where we talk about the latest news, releases, and insights on React and the community.
I was part of the initial private React Hooks preview feedback group, and the invite-only-but-public React 18 Working Group, where we gave feedback on the design, docs, and usage aspects for both releases.
I'm an administrator in the Reactiflux Discord, and have been the primary active moderator in the /r/reactjs subreddit for several years.
I've dug inside of React, the repo, and the internals, including submitting a PR that generated production sourcemaps for React builds, and using time-travel debugging to integrate the React DevTools into Replay's DevTools.
The point of listing those accomplishments is to establish that I have a long history and expertise around how React is developed, what's going on in the React community, what's happening inside the React team, and trying to help people learn React and Redux.
Biases and Caveats ๐︎
Since this is the Internet, I'll try to preempt some concerns folks might have with me writing this.
I am most definitely not always right, and I'm definitely going to end up describing some things incorrectly due to limited knowledge, misunderstandings, or over-summarizing. That said, I'm writing this as a best-faith effort to describe history, motivations, and behaviors as honestly and accurately as I can.
in more detail:
More Detailed Biases and Caveats
Since I maintain Redux, that does bias my own opinions to how React gets used, as well as the kinds of problems I deal with.
While I've used React in some form consistently since 2015, my own experiences using React have become more limited and more niche over time. Most of the React apps I've worked on have been internal tools with limited distribution, and mostly "desktop-style apps in a browser" - in other words, true SPAs without even any routing or CRUD-type behavior. I did work on one CRUD/dashboard-style app, but it was limited in scope. I've never built apps with huge audiences, never used SSR or RSCs in practice, never had to worry about i18n or other large-scaling concerns. I've spent much of my time working on libraries and developer tools, and much less time in the day-to-day of "typical" React app development.
I've read and been involved in inside-baseball React community discussions that the average React app dev never hears or cares about.
I've had personal interactions with the React team online and in person that have been both very positive, and very negative and frustrating. These color my own perspectives. But, I've also had enough discussions with other members of the community to have good confidence that many others share my concerns and opinions.
My normal writing style involves linking as many references and sources as possible. For this post I'll try to do that, but a lot of these historical descriptions and observations will be difficult to find specific sources for, so please trust that I'm doing my best to describe them accurately even if summarized.
My Mindset Writing This Post ๐︎
This post has been very difficult to write.
In Part 1, I was mostly defending the React team's actions and statements, or describing them observationally. Here, I am personally involved in some of these discussions, and some of them ended up being directly frustrating. Additionally, these interactions did involve specific React team members.
I'm not trying to burn bridges, or angrily point fingers! My goal here is to improve the communications and relationship between the team and the community, not tear things down, and I'm taking the time to write all this out because I care about React and the community.
But, this requires that I recount examples of how interactions were handled, and for the bad cases, show how those led to frustrations in the community (and hopefully offer suggestions how how those could have been avoided and things could be improved). To keep this from getting too personal, I'll refer to people as just "a React team member" in those cases, rather than naming them specifically. (I'll link some of the discussions if possible, but the main points are about what was said rather than who said it.)
I'm also not trying to diminish the amount of effort the React team has put in. I understand most of the constraints they're under (especially since I also maintain a widely-used library, have dealt with rewriting docs, and shepherded an ecosystem through upgrades and changes). I've seen their work, I've talked to them in person. I know they care about building a great tool, teaching it, and working with the community. But that's also what makes some of these interactions confusing and frustrating, in times where things came across in negative or opposite ways, or seemingly obvious steps were neglected or missed.
On that note, I'm happy to report that as I was writing this post, the React team directly reached out to me to hear my feedback and concerns. We had a very positive and open discussion about many of the topics in this post, and I'm optimistic that we can work together to improve things going forward.
One more caveat to this section. A lot of these topics involve significant amounts of debate or info that were originally posted on Twitter. Sadly, due to several React team members intentionally leaving Twitter and nuking their accounts, most of their tweets are now inaccessible. I've found some of them embedded in Discord discussions and similar places, so I'll try to quote a few where possible or link to the parts of those discussions that are still online, but most of that will be going from memory.
I'll try to cover points in roughly chronological order, but there's a lot of timeline overlap between them (especially around 2022-2023).
RFCs and PRs vs React's Vision ๐︎
The React team introduced the public RFC process in Dec 2017. At the time, they said:
the goal is to allow React core team members and community members to collaborate on the design of new features. Itโs also intended to provide a clear path for ideas to enter the project:
- Create an RFC document detailing your proposal.
- Submit a PR to the RFC repository.
- Incorporate feedback into the proposal.
- After discussion, the core team may or may not accept the RFC.
- If the RFC is accepted, the PR is merged.
Who can submit RFCs? Anyone! No knowledge of Reactโs internals is required, nor are you expected to implement the proposal yourself.
Unfortunately, the RFC mechanism failed as a way to solicit actual feature suggestions from the community, and realistically it also largely failed at its goal of getting community feedback on React-submitted RFCs.
Lack of Meaningful External RFCs and Comments ๐︎
If you look at the list of merged RFCs and ignore typo fixes, I can only see a single "community-submitted" RFC that was merged. That was the "lazy context propagation" RFC by Josh Story, who was not involved with React at the time, but later joined Vercel and currently works on React's server functionality.
The React team did acknowledge this fact when Dan filed a README update that clarified expectations for the RFC repo, summarized as "RFCs from the React team have gone through extensive iteration, we only post them when we're confident in the design - the RFC is to give the community a chance to offer feedback. Community RFCs might get looked at, but probably don't match what we're looking for".
This ties back to how React is an open-source and mostly-publicly-developed project, but the planning and iteration is essentially all internal to Meta/Vercel.
Similarly, the goal of getting community feedback on React team RFCs feels shaky too. Most RFCs I've seen posted get several hundred comments, most of them are complaints about the naming, the React team says "we don't think any of this needs changing", and then the RFC is merged and the feature gets released as-is.
To be fair, most of the community-submitted RFCs and other similar suggestion issues are not well thought out in the first place, and it's certainly unrealistic to expect RFCs to be merged and implemented just because someone submitted one. Still, it's clear that the intent here didn't work out as originally planned.
Difficulty Contributing to React ๐︎
Similarly, it's also clear that very few PRs to React itself ever get accepted. I semi-frequently see people say "I want to learn the React codebase so I can contribute!" We unfortunately have to tell them "React is not a good project to contribute to. The codebase is complex, there's no low-hanging fruit left, and most likely your PR won't align with the React team's vision". As with RFCs, most external PRs I see are very low-quality and not worth merging, but even actually useful PRs tend to languish.
I have a personal example of that. React had always shipped bundled and pre-minified production artifacts, but that made production code impossible to read or debug. My day job is at Replay.io, a time-traveling debugger for JS, and we rely heavily on apps having sourcemaps to debug them properly. Since React didn't have sourcemaps, it was generally impossible to meaningfully debug back upwards into minified React code.
I filed a PR to rework React's build pipeline and add production sourcemap support in March 2023. This was something that had been requested multiple times by the community, and had a clear benefit. I'm a known figure in the React community. While I didn't expect the entire React team to drop what they were doing and push the PR through right away, I did at least hope that it could be reviewed and accepted at a reasonable pace.
Dan Abramov did respond to the PR a couple days later and offered some initial review feedback. I fixed the issues, but we then got stuck in a question-and-answer loop regarding one specific change I'd made to work around a failing internal React DevTools test.
Unfortunately, at that point, Dan went on vacation, and shortly thereafter announced he was leaving Meta. From there, the PR got lost in the weeds. Several months went by. I worked on backporting the sourcemap changes to React 18.2, and also left some "any further questions?" comments on the PR, but no responses.
Finally, in October, I was at React Advanced in London doing a presentation about integrating the React DevTools into Replay via time-travel. It turned out that the one active React DevTools maintainer (Ruslan) was in attendance. We talked afterwards, I described some of the work we were doing at Replay, but also brought up my seemingly-ignored production sourcemaps PR. A few days later, Ruslan picked up that PR, finished reviewing it, and was able to help push it through and merge it.
Clearly there were extenuating circumstances here with Dan having started to review my PR, then going on vacation and leaving Meta (and taking something of a break from active React work). Still, it was frustrating to see that a fully useful PR that would benefit all React users was generally getting ignored or left to sit. And, the only reason it did get merged was because I happened to have an in-person conversation with the single most relevant React team member at Meta. Had it been anyone else filing the PR, that probably wouldn't have happened.
Hooks Preview and Release ๐︎
I first found out about React hooks when Dan Abramov messaged me asking for feedback on an untitled set of WIP docs. I pretty quickly recognized what was being proposed - function components were getting state and effects!
Later, leading up to ReactConf 2018, there was an invite-only Facebook group of community members who were given a chance to play with preview builds and offer feedback on the WIP docs. Most of the group were also React ecosystem educators.
The discussions were good, and I think we provided some useful feedback. However, it also led to many of the educators taking advantage of their knowledge to launch posts or courses the minute hooks were announced, giving them a first-mover advantage.
Overall I think this was a reasonable attempt at getting feedback from the community, but it maybe could have been organized a bit better.
Suspense, Concurrent Rendering, and useSyncExternalStore ๐︎
In early 2018, the React team organized a call with three of the larger state-related projects at the time: Redux (myself and Tim Dorr), Mobx (Michel Weststrate), and Apollo (Peggy Rayzis). I believe Andrew Clark and Brian Vaughn were representing the React team, with Andrew doing most of the talking.
Andrew specifically warned us that React's upcoming "Concurrent Mode" and its ability to split up render passes could lead to a problem called "tearing". Tearing is where part of the component tree renders with one external state value, and the rest of the tree renders with a different value, leaving them inconsistent. His explanation made it sound like this was an extremely bad problem.
Because they'd reached out ahead of time, I began thinking of ways we could mitigate this. In my mind, I was trying to "skate to where the puck will be", and make sure that React-Redux was updated to fix this.
I actually made a visit to Facebook's offices a couple months later during a trip to SF. Andrew drew a bunch of explanatory diagrams on a whiteboard and walked me through how tearing could occur to help me grasp the concepts, and that was very helpful.
I don't know what other libs did about this at the time. On my side, it drove the design of React-Redux v6 and the way it passed every new Redux state value down via modern Context... and unfortunately that approach turned out to be the worst possible approach for performance :( That led to me rewriting React-Redux v7 to use the newly-released hooks to manage subscriptions inside of connect to restore perf.
In mid-2021, the React team had additional calls with community members as part of the React 18 development process. I think those calls may have even been semi-public. A couple of the calls specifically focused on how React-Redux v7 implemented its subscription model.
The React team had previously added a useMutableSource hook as the intended solution for external state and tearing with Concurrent Mode. However, after we described React-Redux's constraints, they decided that useMutableSource's design wasn't the right approach. They shifted to a different design and behavior, which they called useSyncExternalStore.
At that point the React team had designed useSyncExternalStore, but hadn't implemented it yet. In order to speed up implementation, they needed feedback on actual usage. Since the uSES subscription behavior was explicitly modeled after React-Redux's useSelector implementation, Andrew and I teamed up. He quickly implemented a first pass at uSES and published an alpha. I began working on a prototype React-Redux branch and converted useSelector to wrap usSES, then looked at how many of our tests failed and requested uSES changes to support our use case. We repeated this a few times, and pretty soon I had useSelector working as it did previously, but with all the logic delegated to uSES. Part of the theory here was that if it worked well for React-Redux, it ought to be sufficient for any other external state library to talk to React too.
Overall, this was a great experience! We got advance notice and direct reach-outs telling us about upcoming React changes that might affect us. There were specific discussions where they solicited additional feedback, and those resulted in specific changes to their development plans to support libraries in the community.
React 18 Working Group ๐︎
React 18 was a very significant major release. It had many new features, breaking changes, and behavior improvements. Because of that, and somewhat in reaction to how the private "hooks preview" group had gone, the React team tried something new: the React 18 Working Group.
Like the hooks group, the React 18 WG was invite-only. However, this time all the discussions were themselves public, in a Github repo Discussions section. There was a private Discord server, but that was solely used for some organizational matters. The invite group started with a good batch of 50+ well-known community members, but also added many more invitees over time based on suggestions. This ensured there was a broad representation of people, experiences, and ecosystem contributors.
The React team posted several discussion threads themselves, and all of us invitees were free to post threads as well. Additionally, we were encouraged to look for questions outside the WG, and repost them as threads in the WG ourselves, to act as "the voice of the community".
This was also a great experience! Since the React team was specifically posting threads and answering questions (as well as looking at submitted threads), we had some detailed discussions and got answers quickly. And, since posting was limited to invitees, that kept the signal:noise ratio very high. Discussions stayed on topic, there weren't any spam or low-effort messages, the entire community could read and follow along, and the Discussions section was indexed and googleable.
The Decline of Create React App ๐︎
Create React App was launched in late 2016, and quickly fulfilled its goal of being a fast way to start a reasonably-configured React project with a single command. It became the standard toolset used in React tutorials online, and was also pretty widely used in production apps as well.
However, by 2020, CRA began to fall into disrepair. Other newer build tools were coming out that were faster. While CRA was in the Facebook Github org and had been started by React team members, the remaining maintainers didn't even work for Facebook. It took a very long time to release CRA's upgrade from Webpack 4 to Webpack 5, which finally came out in Dec 2021.
After that, CRA maintenance basically stopped. Issues piled up, and community sentiment began to turn against CRA.
In Jan 2023, Theo Browne posted a React docs PR to replace the CRA recommendation with Vite instead. That PR went viral, racking up thousands of reactions and numerous comments, as well as significant debate over which tools should be recommended and how to describe them in a "Getting Started" page.
Eventually, Dan Abramov responded with an epically lengthy and detailed explanation. He recapped why CRA was originally created, described how CRA had problems because it was only designed to create SPAs and didn't provide enough structure, how newer React frameworks solved that, and that the React team was now thinking of React as more of "an architecture" than just "a library". He also listed 5 possible futures for CRA: "create a new framework", "deprecate CRA and maintain a Vite template", "deprecate CRA and suggest React frameworks", "make CRA use one framework", or "turn CRA into a meta-launcher for other framework tools". At the time, he said they were considering the "meta-launcher" option.
At the time, the "switch to recommending Vite" PR was closed...
and then nothing happened.
CRA was not actually marked as deprecated. It was not turned into a meta-launcher. The repo was essentially abandoned and unmaintained, but not archived or locked. Issues continued to be filed and were never looked at. The docs were never updated.
The React community collectively absorbed the knowledge that "CRA is dead", but it became oral folklore passed around - "oh, everyone knows you shouldn't be using CRA any more". But the CRA CLI was still there, and working. For the time being...
Building the New React Docs ๐︎
React hooks were announced at ReactConf in October 2018, and released in React 16.8 in February 2019. The React community enthusiastically jumped on hooks the moment they were announced. Within weeks of the announcement, users were creating libraries of reusable hooks, and finding ways to add hooks as part of existing packages, even though they weren't stable yet.
By the end of 2019, our survey of Reddit /r/reactjs users concluded that 63% of respondants were already primarily using hooks, with another 17% saying "mixed usage". And hooks hadn't even been stable for a full year yet! It was clear that hooks were the future of React.
And yet, the React docs at reactjs.org still taught class components as the default, and the hooks docs section was buried in a sidebar. I started seeing complaints that the React docs were becoming outdated, such as:
When we decided to convert our React curriculum to React Hooks, one of the biggest stumbling blocks we ran into was that almost all of the guides, tutorials, and blog posts about React Hooks are written with the assumption that the audience already knows React. Most resources are written from the perspective of โHow to switch from class-style React to hooks-style Reactโ, not โHow to learn hooks-style React from scratchโ.
https://kickstartcoding.online/learn/articles/i-converted-reactjs-org-to-use-hooks/
In fact, that comment was made by a community member who forked the React docs and rewrote all the examples with hooks in September 2020. The "React with Hooks" docs site port didn't actually change any of the page structure, so it was the same tutorials and explanations, but even just having those examples changed to be function components made the content more relevant. Community members (including us in the Reactiflux Discord) actually began pointing beginners to the "React with Hooks" site as a recommended learning resource.
It took until October 2020 (a full year after our survey showed widespread hooks usage, and two years after hooks were unveiled) for the React team to announce they were rewriting the React docs from scratch. This was exciting! Not just "show hooks-based examples", or "teach hooks from the beginning", but a completely rethought React docs site with an even better tutorial!
Many people worked on the new React docs, but in particular, Dan Abramov and Rachel Nabors poured massive effort into planning the content and figuring out the right way to teach React. But, that much effort took time, and the work was being done internally at Meta. This led to the community getting restless and wondering when the new docs would be ready.
The new docs went up at beta.reactjs.org in October 2021. The first releases had chunks of the tutorial content, with the rest added over time. It quickly became clear that the new beta docs tutorial was vastly superior to the existing legacy tutorial, and the community began pointing beginners to the beta docs as a better learning resource.
However, even as the beta tutorial matured, the beta docs weren't linked anywhere in the existing docs. I specifically made several suggestions to Dan and other members asking to link the beta docs as a top banner across the site, or at least add callouts on the old tutorial pages saying "We have a new better tutorial over here!", but that didn't happen.
Docs progress eventually stalled. The remaining content was tricky to write, and really needed React team members to do that writing rather than trying to delegate to a tech writer. Unfortunately, that left the docs in a split limbo, still with the existing docs teaching classes, and no visible indication that the beta docs existed or were better.
Finally, in March 2023, the React team announced the public release of the new docs at React.dev, and migrated the old docs to a legacy site.
Ultimately, the new docs are a massive improvement. The tutorial is comprehensive, carefully designed, well explained, and has numerous interactive sandboxes and example challenges. The API reference is more detailed, and covers common use cases and pitfalls.
I think the React team honestly didn't expect hooks to be adopted as quickly as they were. It was clear from the first hooks announcement that this was going to be the future of React, even though they were very careful to say "you don't have to rewrite anything now, your code still works fine, hooks can coexist with classes" (and this was very intentional - they'd learned their lesson from the Angular 2 fiasco). 2019 was full of technical work on Concurrent Mode, and React 17 in 2020. So the 2-year gap between announcement to "let's rewrite the docs to teach hooks first" is understandable. But, the initial delay in deciding to rewrite, coupled with the very lengthy rewrite time, led to a lot of community frustration asking why the docs weren't keeping up with actual usage patterns.
The avoidance of linking the beta docs visibly in the old docs is harder to understand, and similarly, the delay in hitting the button to switch the new docs to be live. I'm very aware of how hard it is to write good docs content, especially when your library is widely used (having re-written and updated the Redux tutorials from scratch). That said, I also can't help but feel that there were some significant "perfect is the enemy of the good" issues here. The content was good enough to be useful, and the community was in widespread agreement that the beta tutorial was a huge improvement. Adding a couple banner or callout links to the old docs would have both pointed readers in the right direction, and cut down on the "why are the docs still teaching classes?" complaints. For the final switch, the last few pages were mostly API references that could have been stubbed out, or even had community members help contribute explanations.
React.dev and "Frameworks" ๐︎
The release of the new React docs was a huge milestone. However, it also coincided with the React team's newly-stated shift from having no opinions to saying "you should always use a framework".
Docs Setup Page Changes for "Frameworks" ๐︎
The biggest evidence of this change was the completely rewritten docs instructions on starting a new project. The old docs "Create a New React App" page said:
The React team primarily recommends these solutions:
- If youโre learning React or creating a new single-page app, use Create React App.
- If youโre building a server-rendered website with Node.js, try Next.js.
- If youโre building a static content-oriented website, try Gatsby.
- If youโre building a component library or integrating with an existing codebase, try More Flexible Toolchains.
and:
Create React App is a comfortable environment for learning React, and is the best way to start building a new single-page application in React.
The freshly-released React.dev "Start a New React Project" page, on the other hand, started with:
If you want to build a new app or a new website fully with React, we recommend picking one of the React-powered frameworks popular in the community. Frameworks provide features that most apps and sites eventually need, including routing, data fetching, and generating HTML
and listed four "Production-Grade React Frameworks": Next, Remix, Gatsby, and Expo (for native).
A Strong Push Against SPAs ๐︎
However, there were no instructions on the page for what to use if you want to learn with React. This page is part of the "Learn React" category in the docs, and the tutorial pages are in the sidebar. But there weren't any instructions on how to create a project for learning purposes. At most, there was a "If you're new to Next, see the 'Learn Next' tutorial" link.
Additionally, the page had an expandable details section labeled "Can I Use React Without A Framework?", with several paragraphs saying "yes, but we don't think it's a good idea".
And buried at the end of that section was this statement:
If youโre still not convinced, or your app has unusual constraints not served well by these frameworks and youโd like to roll your own custom setup, we canโt stop youโgo for it! Grab react and react-dom from npm, set up your custom build process with a bundler like Vite or Parcel, and add other tools as you need them for routing, static generation or server-side rendering, and more.
So, not only did the new setup page not list Create React App, but the closest equivalent tool (Vite) wasn't even listed as a meaningful option in the outer section of the page. Instead, it was buried as a mere mention at the bottom of this expandable explanation.
I'd also say that the phrase "unusual constraints" is very poor here. SPAs had been the standard architecture in the React community since the beginning. CRA and Vite are commonly used. How is building an SPA suddenly an "unusual constraint"? There are many reasons to want an SPA, from architectural to business reasons to simplicity of learning. Those aren't "unusual" - those are all common use cases.
And beyond that... note the phrase "we can't stop you".
This phrase immediately stuck out to community members reading the new docs (including myself), and there was quickly agreement that this was extremely poor phrasing. It came across as a passive/aggressive insult, along the lines of "well FINE, if you really want to do things your own way I guess you can, but it's a BAD IDEA!". Which, frankly, is very insulting to readers and the community - both the actual phrasing, and the general relegation of SPAs as apparently no longer being an acknowledged and supported way to build React apps.
This really was a huge shift in messaging. We went from "use CRA for learning and SPAs" one day, to "only ever use frameworks" and no mention of SPAs the next.
Negative Reactions from the Community ๐︎
This change, especially with the "we can't stop you" phrasing in particular, made many of us in the community very frustrated. This led to multiple community members starting to debate and argue with the React team, trying to convince them to update the docs to both remove that wording, and add a section for "Single-Page Apps" with a recommendation for Vite (and maybe a couple other tools like Parcel).
As a specific example, in June 2023, a Twitter thread started with the question "is this React's Angular 2 moment?". That led to a long chain of replies and arguments.
Just prior to this, I had had some in-person discussions with a couple React team members acting in a DevRel role at conferences, where I had expressed multiple frustrations with the docs process and the discussions around React Server Components (see below), and offered multiple suggestions for improving the messaging. Another React team member was already debating things in this thread, and I replied with "it feels like y'all are completely ignoring / hand-waving away existing SPAs, folks with non-Node backends, etc. The messaging here is really bad.".
Another user chimed in with some specific critiques on the docs page, and offered a concrete suggestion:
The presumption that someone wants to eventually add server-anything rubs folks wrong. Adding a framework to help build the exact same SPA we do today feels like an unnecessary premature optimization. Introducing a meta-framework is not an architectural decision to take lightly
just pointing out what's making people uncomfortable. http://react.dev's tone tries to convince you it's a bad idea. Definitely understand trying to communicate the risks and consequences with the decision. But I think it could be done in a less discouraging way.Turn "Can I use React without a framework?" into a normal "Without a Framework" section. Remove the expansion panel and show the text. Revisit the wording.
"We can't stop you"?! Come on.
Feels disingenuous to sweep todays SPAs under "unusual constraints or not well served..."
I echoed and quoted that recommendation elsewhere in the thread, but that either got ignored or argued against.
I ended up making some very strongly worded statements about the overall poor messaging around RSCs, the insulting tone of voice, the ignoring of well-intentioned user feedback, and the lack of sympathy with the community's expressed frustrations. After posting that, I got several DMs on the side from folks saying they agreed with my statements, and that the overall tone and attitude from the React team was very "antagonistic and unprofessional".
The user who made that docs page suggestion also described how this shift in React team messaging was concerning and felt exclusionary:
In some ways React is having its AngularJS moment. Teams are using this time of instability and uncertainty to shop around for alternatives. We certainly are.
React is great. It's the strong server & framework alignment tone change that's concerning to communities. The server-neutral aspects that made it what it is today suddenly feel second-class. (SPA routers & loaders are a mess & underserved!)
It's not about React or Vite. It's the ecosystem. It's painful to realize that React won't encourage the traditional "non-framework" as strongly as the "new ways". The "React without a framework" section is tucked away in the docs and depressing.
As a non-Node backend company we see those docs as a sign that we don't align with React's primary direction anymore. Framework endorsements are a big enough change to cause teams to reevaluate entire stacks. React is great, but its influence has limits on architecture. It's not "wrong" for React to go this direction. But we can't pretend that non-Framework React usage is now a second-class concern. How long until it's not a viable option? It's uncomfortable. So, we look for safer bets. What would you recommend a non-node backend company do?
https://x.com/vyrotek/status/1649097699696992256
Similarly, in another thread, Dan said:
โwhy not recommend viteโ we do recommend it, for existing projects adding a bit of react to their pages. if youโre creating a new application today with more than a single route, a template that produces an empty HTML + monolith chunk of JS is years behind
https://twitter.com/dan_abramov/status/1648518471083495425
which led Parcel bundler developer Devon Govett to give reasons why not all apps need SSR:
The reason client rendering is still popular is that it is so much simpler than SSR. SSR can be a huge pain โ dealing with hydration, environment differences, effects not running on the server, etc. For some apps, the DX of CSR outweighs the marginal UX benefits of SSR.
Frameworks have simplified SSR a lot and I hope they continue to do so. But a lot of whatโs hard is dealing with differences between the browser environment and the server environment. Missing APIs, different behavior, etc. It needs to be completely transparent.
https://twitter.com/devongovett/status/1648680262400704517
Finally, React team lead Sebastian Markbage also said at the time:
When a community of consumers grow large enough, it's interesting what happens with ownership. I think there's an argument to be made. It's that at some point the community bought into something and you can't change that from underneath them. They own what they bought into. From that perspective, if we as maintainers want to go a different direction, we should have given it a different brand, even if it's backwards compatible.
https://twitter.com/sebmarkbage/status/1673767392369844236
That felt to me like an acknowledgement that this was a drastic shift in direction, and it was going against community expectations. But that never led to any shift in messaging.
Fallout from the Framework Messaging Shift ๐︎
Ultimately, the "we can't stop you" phrasing stayed in the docs for over a year before it was finally tweaked. However, to this day, the only mentions of Vite are that tiny mention at the bottom of the "Use React Without a Framework?" expandable section, and another brief mention on the "Add React to an Existing Project" page.
This has continued to be a sticking point, and there have been further arguments and debate around this even within the last couple weeks (as described later in this post). Some recent quotes that show the lingering effects of this decision:
"Framework" semantics get in the way of progress way too much with React and I'm really tired of the "you must be this tall" narative from react.dev. Tools that drastically aid you to be productive with React deserve a seat at the table. Vite is just the obvious start among many other tools. .... I keep using React and fighting to support it and shape it, but recently it has felt more than ever that the future of React is not in the hands of its users.
https://bsky.app/profile/tannerlinsley.com/post/3lgjhvmryyo2i
and:
I always try to give React team benefit of the doubt that they just genuinely believe the framework-dependent patterns they are pushing for the at the best interest of all React users, but after a few years the elephant in the room just grows bigger: what if they wereโฆ actually wrong?
https://bsky.app/profile/evanyou.me/post/3lgn4xgps6c2m
From my perspective, the React team does genuinely believe that this is the right way to use React, but that's clearly at odds with a significant part of the community.
I'll note that after some of the arguments in 2023, members from the React team did specifically reach out to me and ask me to share some feedback in DMs. That led to me sharing links to numerous community discussion threads over the next year, giving examples of how people were confused and concerned with the push for frameworks, questions around RSCs, and other related topics. I did appreciate that reach-out, and I think they took my feedback seriously. But, I also didn't see much visible evidence that anything was being done in response.
Overall, this entire saga has been maddening, and it actually continues further down.
React Server Components ๐︎
Developing React Server Components ๐︎
The React team first announced the concept of React Server Components in December 2020. It took almost 2 years for Next 13.0 to come out with the first official beta release of RSCs in the form of the new App Router, and another 6 months until Next 13.4 officially declared the App Router as "stable" and ready for production in May 2023.
It's worth noting that some of these features were announced at Vercel's NextConf. This is understandable, given that Next is built by Vercel, but it also contributed to the confusion - we had "this is the first stable release of React Server Components", but it was being announced by Vercel and not the React team directly. Of course Vercel is going to want to loudly trumpet a major new feature, especially if it's groundbreaking, but even allowing for the fact that RSCs require a framework for implementation, this seemed like an inversion. This is also when the "I think of the upcoming Next.js release as the 'real' React 18 release" comment was posted. And, as I noted earlier, seeing React team members merging PRs into React the night before NextConf did not inspire confidence from those of us watching, in terms of either stability or process.
To make things more confusing, the version of React that Next used in the App Router wasn't even a stable release of React. React 19 was still in relatively early development, but the RSC features were considered sufficiently ready that they could be used. But, if there's no stable release, how do you use it? React has shipped near-daily "experimental" builds for years, which have all of the WIP feature flags in the codebase enabled. We've actually used experimental React builds in Replay's frontend, so those work. But, that's not stable enough for real-world beta or production usage.
Instead, the React team came up with a new "canary" build channel, which they also announced in May 2023 the day after Next 13.4 went live. "Canary builds" were releases that selectively enabled specific still-in-development features that they considered "stable enough for frameworks to use". The idea was that many of the features slated for React 19 weren't ready or needed more combined pieces to work right, but the features that were ready could be published in a pseudo-stable release.
However, those features might still be subject to change and have rough edges, so it would be up to a framework to pin a specific canary release as a dependency, and do whatever work was needed to wrap the features it used and make things fully suitable for actual users. Canaries were not guaranteed to be stable across versions - updating to a newer canary could break things. On top of that, there was no actual changelog or details on what features were turned on in any given canary release, or what was changing between releases.
This entire process ended up being extremely controversial within the community. There have been repeated arguments over "how can you claim this is at all stable if it's not in a full release?" and other similar points.
As Astro creator Fred Schott noted:
Let's say I'm a framework author and I want to use the new React canary (prerelease) inside of a stable release of Astro:
- no documented canary changelog
- no documented canary release notes
- no callouts to what's breaking between releases
- missing official docs on correct behavior (no docs on server components, server actions, etc.)
This is all 100% fine for a canary/beta framework, but to call any of this stable and safe for production is detached from how people actually build frameworks or websites.
https://x.com/FredKSchott/status/1673722399278403584
and Parcel creator Devon Govett:
It may break things in third party libraries too, not just the framework itself. Already happened to React Aria for example. This is not FUD, itโs a real concern that frameworks are shipping breaking changes to React in semver minor releases.
I think ideally the versioning would match between React and Next. The problem is that Next is marking it as stable but React is not. Either Next should be releasing with matching canary versions, or React should be releasing stable versions IMO. Otherwise itโs unclear.
https://x.com/devongovett/status/1673399414126448641
I have a fair amount of sympathy for the React team here. I've commented many times that it's impossible to get much feedback from users with pre-release alpha/beta builds - at some point you have to hit the button to publish a final release, and then wait for people to try it out and report problems (which they really should have helped find much earlier if they'd tried out a pre-release build). So, just for that reason I can see a point in the "canary" concept. Also, given that Vercel was sponsoring the RSC work and Meta didn't / couldn't use them, this was the replacement for the "let's try this out and see what needs to be tweaked" approach they'd used internally.
In theory, any other framework could also have looked at using canaries. However, the canaries in practice just became a way for Next, and only Next, to be able to use the still-WIP RSC features, and left everyone else confused and upset about how things were being managed.
Overall, the debates over "NEXT IS SHIPPING UNSTABLE REACT BUILDS!" became a common point of concern. This was made worse by numerous associated complaints about the actual Next App Router implementation itself - bugs, quirks of behavior, limitations, and Next's multiple levels of caching. Even if those issues were Next problems and not React problems, it was impossible to separate them in the discussion because of how intertwined the App Router's behavior was with the actual RSC aspects, and the association between the two conceptually.
As an example of this, the post React Server Components: the Good, the Bad, and the Ugly looked at some actual examples of using RSCs, and pointed out a lot of places that things could be painful. Some of those were actually about RSCs, others were about Next-specific implementation decisions. The post even pointed out "I just want to emphasize that it is currently very difficult to draw a line between React and Next.js. Some (or many) of these new APIs might look and feel different within a framework that has more respect for standards (ร la Remix)", and also had a long list of pain points just using React on the client side that weren't getting addressed sufficiently.
Documenting React Server Components ๐︎
As the new React docs work wrapped up, Dan Abramov began turning his attention to figuring out what descriptions, mental models, and sales pitches would work well to explain RSCs to the community and to learners. This mostly took the form of Dan throwing out numerous insights, descriptive threads, and "if I described RSCs as $METAPHOR, does that help?" thoughts on Twitter.
Dan's public brainstorming did work well to give him feedback on some of his ideas, as well as his own thoughts on whether a particular pitch or description made sense. However, it also resulted in a general feeling of FOMO amongst the online members of the React community. During some of the threads, there were debates over not just "does this explanation make sense?", but rather "here's why the React team thinks RSCs are so good". Some of that turned into a tone of "RSCs are the best possible set of tradeoffs for React data fetching", with a semi-implicit sense that "all other tools are limited, and maybe even bad" (often tying into the React team's significant push against request waterfalls).
I am admittedly exceptionally online and obsessive about reading posts and discussions, so I will freely admit that I was far more aware of Dan's discussions than the "average" dev on Twitter, and vastly more so than "dark matter" devs who aren't aware that anyone is chatting on social media in the first place. That said, in conversations with other community members, we began to feel frustration around trying to keep up with the firehose of rapidly iterating sales pitches, as well as the overall React team messaging around RSCs.
As a couple examples of this: one of Dan's major pitches was "RSCs 'just' extend the React component model to the server. All React client code is valid RSC code too, you pick and choose where the boundaries are. There's no mental model change, it's still 'just React', passing props from parent to children - it's just that now it extends across the network boundary." Dan later fleshed this out in posts like The Two Reacts and A Chain Reaction, and conference talks like React From Another Dimension.
This pitch does make sense conceptually, and I'll agree that both the mental model and overall usage do match this in theory. You don't have to worry about writing a useEffect that does a fetch and sets state, or managing loading states. You "just" write an async React component that actually calls some method to query a database or hit another service, return some JSX like <MyClientChild data={fetchedData} />, and it all just magically shows up on the client side, with Suspense available to manage the loading boundaries.
But at the same time, saying "there's no added complexity" felt very dismissive and disingenous. In order to reasonably learn to use RSCs, even if you're familiar with React, you now have to start drawing imaginary bounding boxes around parts of your component tree in your head, tracking which ones are Server and which ones are Client, and how they interleave. You now have the ability to write React function components as async, but only on the server. Hooks and Context are not allowed in Server Components, and importing any code that tries to use hooks causes Next to throw errors. CSS-in-JS libraries didn't work with RSCs. Even if the RSC internals do the magic work of transferring the data to the client for you, there's definitely still a significant increase in mental model, scope, and things you have to think about. React itself was increasing in scope and complexity, and the team didn't want to acknowledge this.
There was also a major problem with both a lack of documentation for RSCs, and where the available docs actually lived.
Vercel and Next have a sizeable devrel team, and by the time of Next 13.4's release, they had done a sizeable rewrite of the Next docs to cover the then-new App Router, available as "beta" docs. That included some docs pages that talked about using RSCs, under the "Data Fetching" category, as well as later detailed blog posts like Understanding React Server Components. These were excellent resources, with very helpful explanations of architecture and concepts.
And yet, even though the RSC functionality was part of React itself, the React docs didn't have any information on RSCs. Not "What Are RSCs", not "How Do I Use an RSC", and definitely not "How Do I Integrate My Library With RSCs". Vercel's team did a good job documenting their actual product and some of the overlap with React, but it was extremely confusing to people why there was no info or explanations about RSCs in the actual React docs themselves (which, timeline-wise, had just officially launched a couple months earlier).
There was also another major pain point: lack of a migration story.
With React Hooks, the story was trivial: update to a build of React with hooks (16.8+), and either throw some hooks into an existing stateless function component or convert an existing class to a function. Edit one file, try it out, and the entire rest of the codebase still works entirely as-is.
With RSCs, there isn't a meaningful migration path. Server Components have to be the root of your component tree, and you then decide which subtrees are Client Components. That means you have to buy in to RSCs at a fundamental architectural level, and it's not simply something you can tweak a bit in your project. Additionally, since only Next has had RSC support, and that's only in the App Router, you have to convert your project over to that to even try them out. (I will acknowledge that, as far as I know, Next supports using the App Router and Pages Router simultaneously. That's as close to a "migration path" as I can think of.)
Despite all that, the React team was very insistent that RSCs were ready to go and that people ought to be at least trying them out. In a panel discussion at React Summit US 2023, several team members said that "RSCs are just way simpler and it might take like a year or two, or some time, to convince everybody of this" and "if you donโt start with a server component compatible framework, you cut yourself off from being able to leverage the server later on, without having to do a very rough rewrite". They did say RSCs weren't necessarily right for everyone, but the clear emphasis was that people should be jumping into using them.
The (understandable) enthusiasm from the React team about RSCs, combined with the attempts to work out sales pitches, and the expressed attitude that "RSCs are both the future of React, and a superior approach to everything else", led to many people starting to feel FOMO and concern about being left behind from React's direction, as well as a feeling that "we have to be using RSCs!", even though RSCs had barely hit "stable" yet, and were only available in the pre-release or latest versions of Next.
To pick some examples of this, here's some threads I saw at the time that showed these feelings. First, a random user on Twitter:
After reading the initial github comment around the future of create-react-app by Dan, and a lot of the follow up conversation:
I know that you're not saying that client-side only is SOL, but the feel that I get from everything is that at some point, we have no choice but to look elsewhere.
Perhaps I've missed something (or a lot of things!), but it feels like there's a countdown that I don't know when it will reach 0, so I have to start planning migration now.
I think that a lot of others feel the same way seeing everything around the messaging of RSC. Not RSC itself, but the messaging around the future in relation to it
https://x.com/casperOne/status/1647034921892847616
and similarly, from an experienced engineer formerly at Twitter itself:
Too much of React just sits in "Experimental" status while the core team is out there shouting about how whether someone's implementation of said experimental status is correct or not, but won't actually just implement it themselves. These experimental features are also all they talk about. But are they going to actually ship or just get rolled back for their next hot idea?
React used to be seen as a "build once, run everywhere" framework. Now it's: build separate implementations that need to implicitly work together, and only do it for the web.
Here's a demo! It relies on an external undocumented Webpack plugin that we're not going to talk about.
After a couple of hours of research, I've come to the conclusion that if you want to use React Server Components: don't. And similarly, just stick your head in the sand when someone starts talking about them. It's not worth concerning about them until they're actually usable out of the box โ which might be never.
https://mastodon.social/@paularmstrong@mstdn.io/110231706908191955
and finally Evan You, creator of Vue and Vite:
I think the emotional element here is that users sense from the messaging that the React team no longer trusts the users to make their own architectural decisions - โwe know whatโs better for you.โ You might be right, but that can still piss people off.
https://x.com/youyuxi/status/1649290827309670400
Using React Server Components ๐︎
Both the React and Next teams made specific choices around the design and implementation of RSCs. After iteration on how to specify which files were Server Component vs Client Components (including a couple attempts at using filename suffixes like MyComponent.server.tsx), the React team settled on a pair of JS directives: "use client" and "use server". Meanwhile, the Next team decided that the default behavior for the App Router would actually be Server Components by default, only breaking out to a subtree of Client Components when it encountered a file with "use client". Along with that, Next 13.4 began recommending the App Router as the default config choice when creating a new project via their CLI.
These decisions were understandable. They also made using React drastically harder and more frustrating for the community.
Out of the box, a new Next 13.4 project had a /app folder and some React components that were specifically Server Components. Users would typically then try to add assorted third-party libraries, which often required adding a Context-using parent component such as React-Redux's <Provider>. But, Server Components can't use Context, so that immediately threw errors. Users consistently saw those errors and filed issues against the libraries. For us Redux maintainers, we received numerous error reports like this. Our libraries worked fine! The problem was that users had been pushed directly into App Router projects and Server Components through the chosen defaults, and didn't have any mental model of "This is a Server Component, I can't use Context here". They just tried to follow along with whatever existing knowledge they had or tutorial directions they were following, added a library to their project based on its instructions... and suddenly things would break, and it was never obvious why.
The Next team began to add static analysis to detect imports of hooks or context, but that also produced false positives and broke ecosystem packages too . We actually ended up arguing with the Next team over some of their design choices, and Seb Markbage pushed us to publish separate JS bundles using a "react-server" exports condition just to satisfy their design choices. That was particularly frustrating, giving that I was already in the middle of months of trying to rework Redux's package publishing setup for ESM compat. My Redux co-maintainer Lenz Weber-Tronic got fed up and posted an article on My take on the current React & Server Components Controversy, where he described how much harder it was for us to help our users due to these decisions (as well as other frustrations with the complexities of RSCs, the lack of emphasis on React client functionality, and the pain points for us maintainers trying to deal with React's changes ). We finally settled on publishing poison-pilled bundles that threw errors if imported into an RSC environment and directed users to a Next docs page that was belatedly added with workaround directions, but that ended up causing pain for both our users and us maintainers, and I know many other libraries had similar experiences.
The fact that RSCs were suddenly a default became another point of contention. In other discussions online, React team members tried to argue that "RSCs are opt-in". In some sense, they are. You could create a Next App Router project and immediately put "use client" at the top of the component tree, and everything under there is a Client Component. Or, choose to use the Pages Router instead. But, the defaults pushed you to using the App Router and RSCs, so at best it's "opt-out" instead of "opt-in". Given that, being told that this was all "opt-in" made no sense to us.
Even the names "use client" and "use server" ended up being confusing. On first read, you'd assume it means "this specific component can only be rendered in this one environment". But no, it's actually much more complex and confusing than that. "Client Components" can be rendered on the server as part of an RSC pass. The RSC pass doesn't even happen to happen in "a server app" - technically the RSC payload generation could happen ahead of time, or in a service worker, or somewhere else. It's also not "just this one file" - the directives form a subtree boundary, and all nested imports inside of that file are assumed to have that same behavior until another nested import with the other directive is reached. The interleaving behavior ultimately makes sense once you've wrapped your head around it, but that's a lot of added complexity to throw at an experienced React dev, much less a beginner.
From my standpoint, the combination of "lack of docs" and "pain for the ecosystem" were examples of poor decisions from both the Next and React teams rushing major changes live, and not considering the impact of changing defaults. Realistically, the App Router should have stayed in beta much longer, giving the actual Next functionality more time to mature, as well as more time for ecosystem edge cases to be found and docs to be fleshed out.
The combination of all these factors has been extremely painful for both users and maintainers.
Integrating with React Server Components ๐︎
The React team has always intended that RSCs should be something that many React frameworks would integrate and include. However, with Next being the first mover at building in RSCs, and with much of the behavior and integration being undocumented, it has been difficult for other frameworks or anyone else in the ecosystem to actually understand what's needed, what's optional, and how the pieces are supposed to fit together.
TODO the mostly-dead "Frameworks" group, lack of RSC implementation docs, Dan's "inside RSCs" posts, the Webpack plugin, Waku and Redwood?
Overriding fetch for Caching ๐︎
In October 2022, the React team merged a PR that would monkey-patch fetch on the server to dedupe requests.
To quote the Hitchhiker's Guide to the Galaxy: "This has made a lot of people very angry and been widely regarded as a bad move."
The actual goal of the PR was to allow React apps (in certain specific conditions) to make many calls to fetch for the same data in the same event loop tick, but only actually execute a single request. This was done by monkey-patching the global fetch function, and adding wrapper logic that would check for the existence of a React-based cache map in the component tree, normalize the URL and arguments, and ensure only one actual request was made for that unique combination.
It's worth noting that while this PR was merged to main, it was behind a feature flag and entirely proof-of-concept. My understanding was this was meant to be used in React Server Components, allowing you to make fetch calls from within your async RSC components without having to worry about many components requesting the same data at the same time. To make things more complicated, this was implemented by React team members working at Vercel, and was tied into Next's plans for adding various layers of caching.
However, the JS community has learned the painful lesson over the years that monkey-patching globals is a bad idea. Many early JS libraries and apps monkey-patched globals, and that has resulted in a long tail of compat problems. A good example of this is the infamous "SmooshGate", where an old MooTools monkey-patch adding an Array.flatten method prevented the later standardization of an equivalent method from using that name for fear of breaking old websites.
Given that, it's not surprising that there was an immediate vehemently negative reaction to the news that "React is monkey-patching fetch!". The change was met with widespread disdain and complaints from the community, as seen in this React repo issue complaining about patching fetch.
The React team finally reverted the fetch override in April 2024, but by that time the reputation damage had been done.
Developer Relations, Teaching React, and Roadmaps ๐︎
Many of the issues around communications and interactions revolve around a lack of React team developer relations personnel, lack of relevant teaching content in the docs, and a lack of clarity about React's development roadmap.
Lack of DevRel ๐︎
After some of the arguments with the React team on Twitter in spring 2023, fellow OSS maintainer Josh Goldberg and I were chatting in DMs and Josh had these thoughts (shared with his permission):
Josh: I really appreciate your thoughts on feedback & tone in that Twitter thread. There's a lot of greatness in the new React stuff but I do wish they'd paid more attention to folks like you who know how to give the right kind of feedback on early stage woes ๐
I think there have been three issues on their end that have gotten molded together:
- Not having great first-party React docs for the longest time (i.e. the wait for react.dev)
- Fumbling the early court of public opinion for RSC and Next.js (e.g. allowing "MPA vs SPA" to reign for so long as industry dialog)
- Not correcting the recent court of public opinion for ^^^
Whenever Dan Abramov or similar goes on a podcast, the statements are so much more nuanced & forward-thinking than what most external folks -including thought leaders- IME have been saying. But they've created an absence that people are -inevitably- filing with oversimplifications... and not replacing that filling even though it's actively harming industry dialog :/
it feels like a lot of this falls into the purvue of what a devrel/similar should do. Ripe opportunity for someone who has those skills to join/contract... It's also a great demonstration of why that role is relevant in the first place - you can have theoretically the most advanced framework/library/poc on the planet, but if the community isn't being interacted with well, people are going to have a bad time
From an outside perspective, the React team has never had a meaningful full-time DevRel person, and I think that's a major cause of a lot of these issues.
Dan and Vercel as DevRels ๐︎
Now, there's caveats to that. Historically, Dan Abramov acted as an unofficial devrel for React. For years, Dan was incredibly active on Twitter and elsewhere. He specifically sought out people who were asking questions, patiently responded, offered guidance, explained, documented, and corrected misconceptions. People joked (but meant semi-seriously) that "the real React docs are Dan Abramov's Twitter profile". Sadly, Dan left Twitter for multiple reasons and deleted his account, which both stopped the engagement with the community there and deleted all the valuable comments and info he had written over the years :( He continued answering questions over on Bluesky, but was much more focused on building Bluesky's app and exploring its data architecture.
As one Reactiflux member said:
I would say Dan not being at the front door of the react community is by far our biggest loss, he used to bridge the gap between technical decisions and easily digestible messages
there's no one at his level on a combination of massive popularity capable of giving clear messages and its going to cause issues
perhaps, what no one realized is that dan's biggest contribution was actually being a massive devrel for react.
Along with that, Lee Robinson, Lydia Hallie, Delba Oliviera, and anyone else who's been on the Vercel / Next DevRel team recently, have done a fantastic job reworking Next's docs and adding some of their own explanations as blog posts and videos. For example, this post on "Understanding React Server Components" is excellent, and it's the kind of material that should have been posted directly on the React docs and React blog, not just Vercel's blog.
Beyond that, though... I can think of at least 2 occasions where the React team made some announcement of "we've hired a DevRel!", there were maybe a couple initial comments, and then they were never heard from again. More recently, I know there's been a couple React team members who were considered part-time DevRels, and one actual full-time DevRel who's been there for at least a year or two. However, in all honesty: from my own perspective, I can't come up with anything that they've done visibly in terms of posts, community interactions or other content, the way the Vercel / Next team has done.
I can say that I've talked to a couple of them at conferences, and I think some of their time may have been spent on improving the docs or organizing ReactConf. But it sure doesn't look like they've been actively involved in the community in any of the venues that I'm aware of, and most people I've talked to have that same impression.
Other React team members have social media presences, but those have been much more limited, and some combination of actual technical tidbits, personal comments, and in some cases somewhat snarky humor.
So, overall, it doesn't feel like there's ever been a serious official dedicated React DevRel whose time is spent actively engaging with the community.
"What's Going On with React?" ๐︎
As an extended example of this: from mid-2023 into 2024, there was a strong wave of "what is going on with React?" sentiment going around the React and larger web dev communities. As you've seen by now, there were dozens of overlapping topics being discussed and argued about during this time, ranging from "why aren't the React docs done?" to "why is React 19 taking so long?" to "RSCs are being pushed too hard" to "Vercel is pushing React just to make money", and many more. This can be seen in several frustrated blog posts from various community members during that time period:
- Paul Armstrong: Things I want to see in JavaScript and Frontend development in 2023
- Franรงois Zaninotto: Is React Having An Angular.js Moment?
- Matteo Frana: React, where are you going?
- Cassidy Williams: Kind of annoyed at React
- Tom MacWright: Increasingly miffed about the state of React releases
and these were people who were at least loosely involved with the React community!
Reading through those posts, you could see all those different topics and concerns getting intermingled, as well as frustration as to how the React team's messaging and interactions with the community were being handled.
I actually ended up writing a very long response to Matteo's post, where I gave responses to several of the expressed concerns about React's directions. Ironically, the React team actually thanked me on the side for responding to that post and defending them!. (I even considered writing my own blog post just to describe "here are the 30 different topics that we seem to be collectively arguing about, and what those arguments mean - can we all at least agree on what specific things we're arguing over, for clarity?". I didn't write that, but I was seriously tempted.)
Along with that, there were people outside of React who were upset, such as fans of Web Components and vanilla JS who didn't like React's size, behaviors, or architecture:
- Josh Collinsworth: Things You Forgot (or never knew) Because of React
- Simon MacDonald: Removing React is just weakness leaving your codebase
- Andy Bell: It feels like React is getting a bit of a kicking lately
- Alex Russell: If Not React, Then What?
Now, I'm not claiming that it's the job of a DevRel to run around posting rebuttals to every single negative comment about the tool they represent, nor that having a full-time DevRel would somehow magically change the opinions of thousands of community members and of people who are already antagonistic to React and its ecosystem. Or, for that matter, that having a DevRel would somehow magically resolve all of the pain points of library maintainers (like myself, Lenz Weber-Tronic, Dominik Dorfmeister, Tanner Linsley, and Devon Govett), make us happy with where things are going, and prevent any compatibility issues from occurring.
But, when you are building the single most widely used tool in its category, and have a scale of millions of developers using that tool and a giant community of library and tool maintainers surrounding your project... it sure feels like someone from your team ought to be much more actively involved in responding to discussions and interacting with the community more directly. I'm happy to give my thoughts at any time and answer questions, but it shouldn't be my job to have to do this everywhere when I'm not even part of the React team myself!
To cherry-pick one more example: when React 19 came out, the announcement thread posted in Reddit's /r/javascript immediately latched on to the very dense and hard-to-read description of the new useActionState hook:
https://github.com/facebook/react/blob/main/CHANGELOG.md
useActionState: is a new hook to order Actions inside of a Transition with access to the state of the action, and the pending state. It accepts a reducer that can call Actions, and the initial state used for first render. It also accepts an optional string that is used if the action is passed to a form action prop to support progressive enhancement in forms.
Imagine you're new to front end development and people are telling you to "check out react, they just put a new version!" How would you even start after reading that?
The rest of the thread was full of people saying "I don't understand what this does", "Imagine trying to learn React", and other various confused and annoyed comments, rather than meaningful discussion of what was actually new in React 19.
There's certainly no way to control the comments in a Reddit thread :) But, in an ideal world, I imagine Some React DevRel could have actually been watching Reddit, seen that comment, and posted a reply saying "sorry about that, I just filed a PR to make it more understandable!" That could have both changed the tone of the thread, and made things actually easier for people to understand.
Blogs, Roadmaps, and Update Frequency ๐︎
React has had a team blog since the beginning. The current blog is at https://react.dev/blog , and the original blog with posts from 2021 and earlier is at https://legacy.reactjs.org/blog/all.html/ .
Looking over all the posts over the years, the majority of them have been release announcements. There's also been celebrations of milestones, articles discussing shifts in design patterns, conference plans and recaps, and more.
That said, if you look at the "current" blog, the oldest post is Introducing Zero-Bundle-Size React Server Components from Dec 2020. However, there's only been 13 posts since then:
- 2 conference recaps
- 3 posts on React 18 release plans, migration, and release notes
- React Canary builds
- React.dev docs release
- React Compiler beta
- 2 posts on React 19 migration guide and release notes
- 3 "React Labs / what we're working on posts, from June 2022, March 2023, and February 2024
This is a significantly slower pace of posts than prior to 2021.
The React team has always said that the React blog is the most official communications channel they have. They've repeatedly answered questions with "you don't have to worry about what we're talking about personally on Twitter, or alpha releases, or anything else - anything important will be posted on the React blog". While most of the React team has migrated from Twitter to Bluesky, there is still an official React.js Twitter account to go along with the new parallel React.dev Bluesky account, so all three of those do qualify as "official" React communications channels. But it's the blog they've always pointed to as the actual most authoritative source.
Given that, the overall lack of posts feels like a huge waste of their biggest megaphone for the community. Now, this does match the slowdown in actual React stable releases, so it's understandable that there's fewer release-related posts. But given the amount of shifting in the React ecosystem over the last few years, it feels like there's a major gap in the React team's communications with the community.
Roadmaps and Development Directions ๐︎
One issue here is the very infrequent posting of roadmaps and "what we're working on" updates.
The React team has always had a very tough set of constraints with regards to WIP features. If they keep new features internal until they're 100% done and ship them, people complain no one had a chance to give feedback. If they post an RFC, everyone whines about feature naming, the React team merges the RFC and ships the feature, and everyone whines that they didn't make the specific changes people wanted. If they put up PRs for proof-of-concept features behind a feature flag, influencers and content creators jump on that and say "REACT IS ADDING $NEWFEATURE! HERE'S EVERYTHING YOU NEED TO KNOW ABOUT THIS GROUNDBREAKING CHANGE IN REACT!", even though that feature isn't stable and will probably drastically change or even get deleted without ever shipping. So, I'm fully aware and sympathetic that it's really hard for them to say anything publicly about early WIP / POC features - it draws attention to things that aren't ready, they have to spend time explaining things that aren't done and will likely change, and it distracts from what is ready to ship. And, writing up descriptions of WIP features takes up engineering time that could have been spent working on the actual code.
Having said that, it's also true that the current cadence of "one roadmap / progress update a year" feels entirely inadequate.
I don't have a great answer to this. Personally, I'd like to see monthly updates. They don't have to be huge, or even incredibly detailed. But given the scope and magnitude of the React ecosystem, I think it's reasonable to offer some consistent sense of the directions the React team is exploring or planning on shipping, especially now that 19.0 is out the door.
As for the "WIP features status" idea specifically: in talking with the React team, one idea that has come up several times is the idea of using the "TC39 Stages" approach to describe feature status. All new JS language feature proposals go through a series of numbered stages, where 0 is "someone had an idea", all the way up to 4 as "it's been implemented and shipped and is done, this will be in next year's JS language spec".
I know that it would be more docs work to do, but having a table of the various WIP React features and their status seems like it would be really useful to both users and library maintainers.
Add More Educational Blog Content ๐︎
It also feels like the lack of non-release-related content is a major gap as well.
There's been a ton of community discussion and questions around "why use frameworks?", RSCs, and many other topics. The React blog would have been an ideal place to publish posts answering those questions officially, providing more details and context than what you'd get in a social media subthread. As I said above, I think the "Understanding React Server Components" post that was posted on Vercel's blog really should have gone on the React blog instead - this is exactly the kind of useful and informative content that ought to be getting highlighted!
Or, when good discussions happen elsewhere, do some roundups and summaries. There are already a bunch of React-related email newsletters that do news / article / release roundups, like This Week in React and React Status, as well as the "This Month in React" podcast that I'm part of in the Reactiflux Discord. So, we're not lacking for roundups from around the community. But there were community roundups posted on the React blog in the early days, and some form of that on the React blog would be potentially useful.
Add More Updates on React Team Progress ๐︎
Along with that, there have been missed opportunities to announce further updates to the docs. As one specific example, in December 2023 the React team posted an announcement saying they had added multiple new API reference pages for the upcoming React 19 hooks, as well as things like React's support for the <form> tag and a new "Learn" section page on "Understanding your UI as a Tree".
This was wonderful! New docs pages, filling in gaps in the API reference section, improving the tutorial, adding explanations. This was totally something that should have been front and center on the React blog!
But instead, it was posted... as a Github discussion thread. In the React Server Components Working Group repo. Which is about as much of a hidden-out-of-sight-where-no-one-will-see-it location as I can think of:
I honestly don't understand why this announcement was made in that repo, at all. The only two new docs pages listed that related to RSCs at all were pages on the "use client" and "use server" directives. The RSC WG repo has had practically no traffic or discussions.
If I hadn't happened to see some side mention of that thread getting passed around, I would have had no idea that any of those new pages had been added.
We don't need a blog post for every merged docs PR, but surely it's worth putting up posts when there's some batch of new pages or meaningful content updates made to the docs.
The React blog is sorely underutilized, and it should be a pretty high priority to start publishing more posts and more relevant content here.
Future Solutions vs Current Problems ๐︎
The React team has had a repeated tendency of looking at technical problems, thinking very hard about how they want to fix it, coming up with a future solution that's somewhere farther down on their roadmap... and then responding to community complaints about that problem and requests for a fix with a general answer of "we know what the fix will be for this eventually", and acting like the problem is already solved.
As another maintainer put it: "It's not that they don't care. They care years before we know a thing will happen, and when the thing happens they already have spent so much time thinking about it that they look like they ignore the community, while they just accepted it after years of overthinking".
I can think of several examples of this off the top of my head.
The most obvious one is the pain points of useEffect dependency arrays and the need to kick off data fetches in useEffect, vs the eventual goal of using Suspense for data fetching. The original React Hooks docs page actually explicitly said:
The array of dependencies is not passed as arguments to the effect function. Conceptually, though, thatโs what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically.
https://legacy.reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect
React team members have also specifically stated that the hooks API was intentionally designed with the intent that a compiler would eventually be able to automatically insert those.
It's great that the React team was thinking ahead that way. But, the idea that "someday a compiler will do this" did nothing to address the requirement that users write those dependencies themselves today. Yes, the React "Rules of Hooks" ESLint plugin can help with that, but dependency arrays and the failure modes of "oops I got my dependencies wrong and now my effects are running in an infinite loop" have made this one of the most painful aspects of using React. The good news is that React Compiler is finally a real thing, and should hopefully actually take care of this for us... but that's at least 6+ years of the React ecosystem having to deal with that pain point.
Another example is the useEvent hook RFC. The use case for this was complicated, but roughly put, it would help solve "stale closure" issues by accepting a callback, always returning a stable function reference wrapping that callback, and always calling the latest version of the callback when executed. That RFC was published in September 2022. After lots of debate around naming and semantics, including a possible name change to useEffectEvent, the React team opted to close the RFC in favor of a possible alternate future approach. That's reasonable - not all proposals work out, and sometimes feedback and experimentation do change understanding.
Meanwhile, the new React docs have multiple pages of warning and guidance around the pitfalls of the useEffect hook. As part of that, the "Separating Events from Effects" page actually has a section that specifically describes and recommends using the still-hypothetical useEffectEvent hook as a solution to some of these problems. That feels very awkward to me. There is a callout saying "this is a future API that isn't released yet"... but telling readers "here's how you solve a problem with this thing that doesn't exist" doesn't feel helpful.
As a final example: Dan mentioned in early 2023 that the React team was leaning towards turning CRA into a multi-launcher option. When CRA broke after React 19's release and I raised this as a problem, one of the first answers was "we're still thinking of turning it into a multi-launcher, but that hasn't gone anywhere". That didn't feel like a useful answer. Even if the React team had decided right that minute that "convert to a multi-launcher" was their highest priority task, it would still have taken potentially months to implement and ship that... and in the meantime the existing CRA CLI would still be broken. And in reality, the idea was still very hypothetical / "we've been tossing it around as an option", not something actually on the near-term roadmap.
I do appreciate the React team's thoughtfulness about finding the right solution, not just a solution, and the amount of care they put into evaluating tradeoffs and figuring out the best approach. It's unfortunate that this does sometimes manifest itself as a seeming dismissal of today's users experiencing that problem.
Teaching React in an Age of Frameworks ๐︎
Continuing on the docs theme: as I've said many times so far, the new React docs at React.dev are fantastic! Great explanations, a comprehensive tutorial with in-page sandboxes and challenges, a better API reference section that covers usage and common pitfalls, and much more. Wonderful.
And yet... as amazing as the new "Learn React" tutorial is, it doesn't really do anything to teach beginners how to actually apply their knowledge to the real world.
If you look at the "Learn" section, it's divided into these categories:
- "Describing the UI": component basics, JSX, props, conditional rendering, lists, "pure rendering"
- "Adding Interactivity": event handlers, component state, renders vs commits, updating objects and arrays in state
- "Managing State": declarative UI, designing state structures, using reducers and context
- "Escape Hatches": refs, effects, why you shouldn't use effects and what to use instead, and custom hooks
I still have some quibbles with naming that last category "Escape Hatches", but setting that aside. If we make the (admittedly unrealistic) assumption that a beginner is going through the entire tutorial linearly, they're going to go through the first three categories, and then into "Escape Hatches". They'll read through multiple pages talking about how useEffect is dangerous, read about extracting custom hooks...
and then nothing. The tutorial stops.
There is no final conclusion for the whole tutorial sequence. And there definitely isn't any sort of direction on how to actually take what they've learned and use it in an actual standalone project.
On top of that, all through the tutorial, learners have been writing code in the excellent embedded CodeSandboxes. Those sandboxes do have multiple files in most of the examples, but I don't see a way to add another file - you can only work with the files that were predefined for that example. There is a "Fork" button that actually leads to CodeSandbox itself, but that's not an obvious way to do further edits to the examples, it's not how you'd start an actual real project, and it doesn't give any direction on managing components in files.
Meanwhile, the Start a New React Project page that I've repeatedly referenced immediately directs users into a "Production-Grade React Framework", and most likely Next. Next's docs and CLI in turn will funnel users into creating a brand new Next project that defaults to using the App Router and RSCs...
and nothing in the React tutorial prepares users for jumping into the kind of complex full-scale project setup that you get from scaffolding a new Next or Remix project. Nor does "Use a Framework" and "Production Grade React Frameworks" on the setup page give learners a good idea of what steps they should take to really create a first project.
This to me is a major gap in the teaching flow, and a disservice to learners.
From my standpoint, I don't think Next or Remix are the right tools for a beginner to be using. I would still strongly push for beginners to be directed to create a simple SPA with Vite, where there's fewer moving pieces to have to think about at once.
If I could actually wave a magic wand to fix this, I'd make a combination of changes:
- Add a new "Conclusion / Next Steps" page at the end of the tutorial. This should cover topics like "how do I start a new React project and apply what I've learned?", as well as give some direction on "if you're using $FRAMEWORK, here's the folders and files where your React components should live - you can apply your new knowledge there".
- I would also update the "Start a New React Project" page to specifically point beginners to Vite as the best build tool for creating a learning project.
As we've already seen, that Vite recommendation is something the React team does not agree with :) We will encounter that again near the end of this post.
As an addendum: I actually had a long discussion about potential React docs teaching flows with Ricky Hanlon at ReactConf 2024. A couple of the ideas we tossed around were things like "does it someday make sense to teach React via RSCs first, and then work your way up to client components?", and "what about when React Compiler is stable and widely used? How do you approach teaching useMemo/useCallback and rendering behavior, when the Compiler drastically changes the code you actually need to write, but you still need to understand the mental model without it?". We didn't have answers, but it was good to see these questions being asked and thought about.
Suspense for Data Fetching and use ๐︎
The React team first introduced the concept of "Suspense" in early 2018. The main announcement I know of was Dan Abramov's JSConf Iceland talk "Beyond React 16", where he showed demos of two concepts: "time slicing", which allowed components to render smoothly even amidst high CPU usage, and "Suspense", which allowed users to do async loading deep in the component tree and manage loading state declaratively higher up. At the time, these were first initial POC demos. There was enough progress the React team was ready to show what they were thinking, but far too early to talk about when they would be stable features.
The <Suspense> component itself actually did get released as part of React 16.6 in October 2018. However, at that time the only use for <Suspense> was in conjunction with React.lazy() for code-splitting and lazy-loading individual React components. The release post said:
The Suspense component will also allow library authors to start building data fetching with Suspense support in the future.
This left open the question of "When will 'Suspense for Data Fetching' be available?". Having seen the demos, the community was eager to start using this concept.
However, years went by, and the promised "Suspense for Data Fetching" never materialized.
What Is "Suspense for Data Fetching"? ๐︎
Part of the issue was that it was unclear what exactly the phrase "Suspense for Data Fetching" even meant. What was Suspense, exactly? How did you trigger the behavior? What did "support for Suspense" involve? Were we waiting for React to add some additional functionality first? What pieces were missing?
The early demos of Suspense generally showed a pattern that looked roughly like this:
function MyListItem({ id }) {
const item = someItemCache.read(id);
// render with item
}
From this we can infer a few things:
- Suspense would be triggered from within the rendering of a component
- It needed to involve integration with some out-of-tree cache object
- The cache looked like it would just return a value
- The general approach seemed to involve some sort of key/value lookup
But beyond that, there was no indication of what the trigger mechanism was, or what was actually happening inside of that read() method.
Eventually, people with digging inside the React source, and figured out that the trigger mechanism involved throwing a promise. React already had Error Boundaries as a component tree equivalent of a try/catch mechanism for handling errors, and the Error Boundary implementation required catch actual thrown errors. For multiple technical reasons, the React team opted to build off that approach, and have Suspense be triggered by throwing a promise from within the component. Internally, React would catch that promise, wait for it to resolve, and then re-render the component, which would now see it had the expected data available and continue with rendering. As far as the cache itself, it would presumably have to do some hand-wavy implementation to figure out if there was a result available for that key, and otherwise start a request and then create and throw a promise to wait for the result.
In many ways, this simplifies data fetching usage. There's no useState for tracking a loading flag, or useEffect for triggering a request. In a sense, the component would never even see the case where the data didn't exist. You just write code that assumes the value exists and was returned, and let React worry about when to re-render the component after the data is available, and wrap part of your component tree in a <Suspense> higher up to put the loading spinner at an appropriate place. That also gives the developer much more control over where and when loading spinners appear, like putting them at the boundaries of different panels in the app.
React has always had strong ties to "Functional Programming" principles, and in this case, Suspense conceptually related to a concept called "algebraic effects" (as described by Dan in his post Algebraic Effects for the Rest of Us ).
So that's the theory behind Suspense, and part of the mechanics.
But. None of this was ever fully documented, announced, or encouraged. The "Suspense requires throwing a promise" trick became generally known amongst the maintainer community by mid-2019, as evidenced by Dan actually mentioning that in his post around that time.
Lack of Direction with Suspense for Libraries ๐︎
Purpose-built React data fetching libraries became common in 2018-2019, and especially once hooks came out. Libraries like React Query, Apollo, SWR, and later RTK Query, all settled on a similar API shape: const { data, isLoading } = useGetPokemonQuery("pikachu"). That "query hook" abstraction encapsulated logic for reading a value from a cache, triggering a request in a useEffect if it wasn't available yet, tracking the request status, and re-rendering the component once the data was available.
The React 16.6 post said "library authors can start building data fetching with Suspense support in the future". We were all rather impatiently waiting for "that future" to arrive. But it didn't. There were no further details on what pieces were needed to enable "Suspense for Data Fetching" on the client, or how libraries were supposed to integrate with Suspense.
The React team did publish a set of experimental/WIP docs pages around the future "Concurrent Mode" in early 2019. These pages described what "Concurrent Mode" was supposed to be, how the React team was envisioning having multiple "Modes" with varying functionality, and what "concurrency" would enable behavior-wise. As part of that, there was a "Suspense for Data Fetching" page in that experimental section. It gave some details on what Suspense was, and some notional patterns around potentially using Suspense. It even had a "For Library Authors" section... but all that said was "Although itโs technically doable, Suspense is not currently intended as a way to start fetching data when a component renders. Rather, it lets components express that theyโre โwaitingโ for data that is already being fetched". It gave some theoretical advice on when to initiate fetching, and recommended looking at Relay as an example.
That still did not provide any actual guidance for library authors. It did define phrases like "fetch-on-render" (ie, in a useEffect), "fetch-then-render" (fetch as early as possible then wait), and "render-while-you-fetch" (fetch early and render screens right away while waiting). I think I maybe heard those terms in a couple other places, possibly related to Relay. But, to my knowledge they weren't widespread, and definitely weren't covered in the main section of the React docs.
When React 18 came out in March 2022, the React 18 announcement post only added to the confusion:
Suspense in Data Frameworks
In React 18, you can start using Suspense for data fetching in opinionated frameworks like Relay, Next.js, Hydrogen, or Remix. Ad hoc data fetching with Suspense is technically possible, but still not recommended as a general strategy.
In the future, we may expose additional primitives that could make it easier to access your data with Suspense, perhaps without the use of an opinionated framework. However, Suspense works best when itโs deeply integrated into your applicationโs architecture: your router, your data layer, and your server rendering environment. So even long term, we expect that libraries and frameworks will play a crucial role in the React ecosystem.
As in previous versions of React, you can also use Suspense for code splitting on the client with React.lazy. But our vision for Suspense has always been about much more than loading code โ the goal is to extend support for Suspense so that eventually, the same declarative Suspense fallback can handle any asynchronous operation (loading code, data, images, etc).
So apparently Suspense could be used with "opinionated frameworks", but... how are they implementing this Suspense integration? And what are third-party client-side libraries supposed to be doing to make this work?
Reading between the lines, "Ad hoc data fetching" was a description of the "throwing a promise" trick being used by a third-party library. By this time, multiple libraries had latched onto that approach and were actively using it, even though it had never been documented. The React team was apparently aware of this.
There was a "Suspense in React 18" RFC that had been posted as well, but it was focused on user-facing behavior changes in terms of commits, streaming, and hiding existing content, rather than the implementation details of how Suspense got triggered or used.
The use Hook RFC ๐︎
Finally, in October 2022, the React team published a new RFC, describing "First class support for promises and async/await". This had two aspects: Server Components would be the mechanism for data fetching on the server, via writing a component function as async and running fetching logic directly in the component. On the client side, there would be a new hook named use, which would be the official replacement for the undocumented "throw a promise" mechanism.
The intended use hook usage looked like:
function MyListItem({ id }) {
const item = use(fetchItem(id));
// render with item
}
Conceptually, use was compared to a React-specific await keyword equivalent, "unwrapping" the promise.
The RFC was both welcomed and controversial. There were lots of complaints about the indistinct naming of use, but also lots of questions about intended behavior. For example, to work properly, your fetchItem function needed to consistently return the same Promise instance for the same arguments, so that use could tell when it was actually resolved and read the value. If it always returned a different Promise, that could cause an infinite render loop.
Beyond that, the RFC specifically mentioned:
The way to fix [the new promise reference] warning is to either memoize the async function (with useMemo) or cache it (with
cache, which will be described in an upcoming RFC). ........ We'll update this proposal once the RFC forcacheis ready.Note that most existing data fetching libraries already implement a caching mechanism that is sufficient to avoid this pitfall, so they should be able to adopt the
usepattern without also needing to adaptcache. This is mostly a new concern that arises from calling async functions directly within a component.
The use RFC at least gave us some clarity on where things were headed, as this was the official replacement for "throw a promise"... but apparently there was some additional cache piece that we needed to have described and implemented before we could do anything with our libraries.
To make this more confusing, there had also been previous React team discussion of some kind of <Cache> component that would integrate caching behavior into your component tree. It was unclear if the "cache" referenced here was the same thing, or different, or what they would cache, or how.
Just a few days later, Sebastian Markbage filed a PR to add cache to the React repo. Upon inspection I realized that cache was essentially just a memoizer function that memoized results based on arguments, but with some tweaks to keep the cached values internal to the React tree.
However, the promised "cache RFC" never materialized. And that left all of us data fetching library authors confused and unsure of what steps we could take or should take to actually add Suspense support to our libraries. Was use ready for us to play with? When would it be available? What else needed to be done?
Data Fetching Library Summit ๐︎
Finally, in February 2023, we managed to arrange a "React data fetching library summit" call with the React team. We had maintainers from React Query, Apollo, and RTK Query, as well as Dan and Andrew from React. I mostly took notes, as I didn't know enough to ask good questions or really participate in the discussion. You can see those notes for the detailed version, but my own summary / takeaways at the time were:
- They recommend trying to start with simpler Suspense-specific APIs that don't cover all use cases, and likely separate from the existing
useQuery-type hooks- The Suspense-y model is really focused around "denormalized" / "request/response" scenarios, where invalidating is "throw this whole thing out and refetch it"
startTransition()is a key piece of the Suspense story, because it's basically "start a state update + re-render, but at low priority and this could take a long time". But, there's questions around who should callstartTransition()- does it go in lib code or app code?- There's definitely tension between libs that want to be UI-agnostic, and React-integrated features that want you to buy in to how React does things
Additionally, the React team gave us a verbal go-ahead that "Suspense works well enough that you can start trying to make use of it".
In a lot of ways, that meeting still left us with more questions than answers. We knew the use hook existed, but it wasn't clear how to leverage it: inside our own hooks? return a promise from our hooks and have users pass it to use? And beyond that, what happens when you have cases like data streaming in over time, and it's not just a Promise style "request/response" result? It also felt like the overall design of use was very limited in scope compared to how real-world apps might need to work.
To my knowledge, we never really got further direction or answers on any of those sorts of questions. That left us generally confused and frustrated.
React 19 and use ๐︎
Almost two years later, React 19 finally came out in December 2024. Down in the release notes, there was a section on use that said:
usedoes not support promises created in render.
If you try to pass a promise created in render to use, React will warn.
To fix, you need to pass a promise from a Suspense powered library or framework that supports caching for promises. In the future we plan to ship features to make it easier to cache promises in render.
But once again, no actual library-focused direction on what a "Suspense-powered library" even is or is supposed to be doing.
Meanwhile, the use RFC remains open to this day, without an actual resolution. use shipped, so presumably it's "done", but overall the handling of this RFC has been extremely confusing.
Eventually, libraries did figure out some approaches. React Query has shipped semi-stable Suspense support for a while, with hooks like useSuspenseQuery, and recent support for returning a promise from a query hook that you can pass to use itself.
I acknowledge that it took the React team many years of experimentation and implementation work to figure out all the technical details of Suspense and Concurrent Rendering, and that it's really hard to provide answers to the community when you don't even know what the final shipped APIs and behavior will be. That said, as a library maintainer who has been repeatedly asked "when are you shipping Suspense support for RTK Query?", this entire saga has been painful, and I can vouch that other library maintainers feel the same way.
Its-Not-Fine ๐︎
Context and Reconciler Boundary Limitations ๐︎
After modern React Context came out in 16.8, users discovered a limitation: you couldn't read Context across React renderer boundaries. The most common example of this was using the react-three-fiber renderer for 3D graphics, inside of a ReactDOM-based page. It's reasonably to want to render a <MyContext.Provider> in the web app component tree, and read from it inside the nested 3D component tree, but Context didn't propagate across boundaries.
In 2018, Dan filed an issue for "Support cross-renderer portals". Commenters eventually came up with some temporary workarounds.
Then, in March 2022, the Poimandres developer collective (which builds react-three-fiber, Zustand, Jotai, Valtio, and various R3F-related utilities), published a new package called its-fine. That package intentionally accessed React's undocumented internals (and specifically the infamous __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED object), allowing them to read values from the Fiber tree and pass them onwards. That enabled creating a useContextBridge hook that worked around the Context boundary limitation. The Poimandres devs left a comment in that issue linking to the its-fine library, but also asked for some official solution to the problem built into React itself.
There were no further replies from the React team.
There was another overlapping issue filed in November 2019, "Is it possible to share contexts between renderers?". That had one brief initial response from a React team member, then nothing further through early 2024, as multiple community members tried to figure out workarounds and solutions themselves.
Future Issues with its-fine ๐︎
In March 2024, with React 19 in beta and React 19's release seemingly getting close, a React team member tweeted a link to the its-fine package and said:
A good list of libraries that'll break with React 19 ๐
https://www.npmjs.com/package/its-fine?activeTab=dependents
By itself, this was a reasonable observation. The React team was already planning to rename the SECRET_INTERNALS object to __SECRET_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, both because various packages had been accessing it, and to get rid of the original joke naming. Clearly that meant that its-fine would break with React 19, as would any packages depending on it.
Another React team member then quoted that post and commented:
Narrator: but it was not fine
This felt snarky, but still passable.
The its-not-fine PR ๐︎
What happened after that, however, crossed the line.
That person then actually filed a PR to the React repo that would specifically look for the existence of its-fine in a project, and throw an error if it was found. The PR description was: "cheeky idea for blocking this import".
Let me restate that.
A member of the React team intentionally filed a PR that would destructively break userland code and entire end-user projects if merged and released, as a "joke".
This came across as incredibly uncaring and insulting to the React community. Rather than looking at the problems faced by the community, identifying userland workarounds, and trying to come up with long-term solutions, React team members were celebrating the upcoming breakage, joking about it, and taking the time to file actual PRs that would make things break.
Yes, the PR itself was obviously a joke and was never going to get merged. That doesn't excuse this behavior.
As a library maintainer, when I see someone writing code that depends on my lib's internals, I see it as an indication that there's use cases I should be considering supporting or APIs that I ought to expose. We had this issue with React-Redux's original passing of the Redux store via legacy context, as this.context.store. That was always undocumented and not part of our public API, but many libraries accessed it anyway because they needed to use the store reference. We broke that in React-Redux v6 when we switched to modern context, but we specifically provided a new useStore hook as the public API to solve that use case. I'm not always able to provide an official solution to userland hacks and internals accesses, but it sure is something I take note of as a problem my users would like to have a solution for.
Here, there had been multiple filed issues since 2018, with the community trying to come up with viable workarounds to solve this use case. And not only did the React team never provide a solution for that use case, they celebrated when the main workaround would break.
It was always clear just reading the its-fine README that this was a hacky solution that would break, and both the authors and users knew that. Even if there was no good solution, it would have been helpful to reach out to the maintainers and say "fyi, this will break in React 19 - what are you trying to do and how can we help?".
I replied to that PR with "What would be needed to enable cross-renderer contexts instead?". A few days later, Seb Markbage did write up a technical response with an investigation of what would be needed to enable cross-renderer context support, and why that would likely be difficult for now. That at least addressed the real use case question at hand.
Ultimately, this was extremely poor behavior from the React team. Observations that "this internals access will break in the next major" are very reasonable. Laughing about breaking userland code is not. Intentionally taking time to mock-break userland code as a "joke", especially without actually trying to solve the real problem, is absolutely not "fine".
SuspenseGate ๐︎
React 19 finally reached beta in April 2024, almost 2 years after the last stable release of React 18.2.0.
Just a few weeks later, at ReactConf 2024 in May, React 19 was advanced to Release Candidate. Shortly after that, React team members said online that "This RC is the exact build we plan to ship as final, barring any further issues".
Those words were prophetic.
There had been plenty of canary releases leading up to the Beta and RC announcements, and those canaries were being used in production by Next 13 and 14, so it's true that the code in React 19 had been in use for a while. That said, the jump from Beta to RC seemed awfully fast. As a lib maintainer, we had been waiting for at least Beta before even thinking about trying to work on upgrades and version compat checks with our own libraries, and we definitely hadn't even had time to do that yet by the time it went to RC. It didn't seem like the rest of the ecosystem was likely to have had time to realistically try it out either. As I mentioned earlier, I know from my own experience that very few end users actually try out pre-release versions, so it's really hard to get meaningful feedback prior to actually publishing a release live. What if there were some issue that didn't get caught until after 19.0 went final?
Spoiler: that almost happened.
Changes to Suspense Behavior ๐︎
In March 2023, the React team merged a PR that altered the behavior of sibling components that used Suspense. Prior to the PR, having multiple siblings suspend would act like a Promise.all(), essentially kicking off all of them in parallel and waiting for all of them to complete before rendering the results together. The PR changed that behavior to act more like a serial loop - triggering the first child, waiting, rendering, then moving on to the next child.
The PR itself was done primarily to make incremental speedups for Facebook.com itself. The PR noted that this could make other scenarios worse, but justified the change on the grounds that the React team's thinking about Suspense usage patterns had been changing:
Our original rationale for prerendering the siblings of a suspended component was to initiate any lazy fetches that they might contain. This was when we were more bullish about lazy fetching being a good idea some of the time (when combined with prefetching), as opposed to our latest thinking, which is that it's almost always a bad idea.
Given that lazy data fetching is already bad for performance, the best trade off for now seems to be to disable prerendering of siblings. This gives us the best performance characteristics when you're following best practices (i.e. hoist data fetches to Server Components or route loaders), at the expense of making an already bad pattern a bit worse.
That PR presumably went out in canary builds for the next year, and no one noticed...
Outcry over Suspense Changes ๐︎
until early June 2024, when the community realized that this change existed, and actually made some cases much worse.
I won't detail the entire saga here. Dominik Dorfmeister, the maintainer of React Query, was squarely in the middle of this drama, and put up an excellent post on React 19 and Suspense - A Drama in 3 Acts, which recaps the specific events. But, as a summary:
- Dominik and a couple others noticed that the Suspense change made a couple of examples slower
- They posted about it on Twitter, tagged React team members, and the discussion went viral, including finding out that the change was intentional and not a bug.
- The community realized this did affect a number of projects, and especially
react-three-fiber, which used it to load many 3D assets in parallel - This was right before React Summit Amsterdam. At the conference, "SuspenseGate" was the main topic of discussion. We already had a "React Community Maintainers Summit" discussion event scheduled there. At that discussion, 3/4 of the attendees discussed the technical consequences of the changes, while the rest of us talked about ways to improve the React team's communications with the community.
- During the Twitter debate, the React team noted that the change couldn't easily be reverted - too much else had changed, and it would require a major rework forwards.
- The main fear was that React 19 was almost ready to ship as final, and we'd be locked into this "broken" behavior for years until the next major version came out
Holding the React 19 Release ๐︎
Soon after (and after a lot more heated discussion online), the React team announced that they would delay the React 19 release to fix this:
good news re Suspense:
- we care a lot about SPAs, team misjudged how many people rely on this today
- still recommend preloading but recognize not always practical
- we plan to hold the 19.0 release until we find a good fix
(to clarify: the popularity of SPAs wasn't misjudged; what was is the prevalence of having a single Suspense boundary containing siblings that each initiate different async work โ since you don't run into this if you initiate fetches earlier or if things are in one component)
and later posted a lengthier set of explanations for what happened:
Some thoughts on the suspense changes from 19 RC. Most important: our bad. We got this one wrong, and we heard and sincerely appreciate your feedback. We'll hold the 19 release until we find a good fix.
What happened? The behavior change affected a specific case: a
boundary with multiple children that suspend. In 18, React wouldn't stop rendering at the first suspending child. It would continue pre-rendering siblings. We regularly analyze performance of React apps, and found that this behavior was inefficient in apps that were using the render-as-you-fetch paradigm. In this approach you fetch in eg a route handler, and then suspend if this data isn't ready yet in render.
We extensively discussed the tradeoffs of this change. We knew it could regress in a specific scenario: apps with many lazy-fetching children in a single Suspense boundary. We thought this case was uncommon enough (wrong in hindsight). We decided to ship and get feedback.
Where things went wrong is the next step. We hoped that we'd get feedback via the canary release, which has included this change for many months. But during that time period we've also learned that the canary channel isn't easy enough to consume and few were testing with canary.
The result was that we didn't get the feedback until the 19 RC. Our changelog did call this out (could have called it out more prominently, to be fair), and that's how folks knew to test the behavior. Once we heard the feedback we quickly discussed, leading to where we are.
Stepping back: there are a few things going on here. We need to continue flushing out our story for client data fetching. But there are many great options in this space that support the render-as-you-fetch pattern: more important is getting feedback from the community earlier.
This is harder than it seems (always is) because of the size of our community & many ways people use React. We need to balance info overload while getting a diverse, representative set of feedback.
We also don't want to privilege established players at the expense of making it hard for new libraries/frameworks/educators/voices to emerge. Rushing into a fix could backfire and lead us down the wrong path.
So: we're working on changes to get feedback from y'all earlier. We're exploring a number of ideas including evolving our previous working groups and RFC process. We will definitely also re-evaluate canary to ensure that more developers can try out changes & new features earlier.
This is a wonderful response. It explains what happened, why, what they were thinking about when they made the changes, and how they hope to improve going forward. (It also feels like something that ought to have been on the React blog, not a personal Twitter account.)
And indeed, the React team did delay the React 19 release, and tackle this. After a few months of work, React 19 RC.1 shipped in November with revamped behavior for parallel sibling Suspense, adding a new "pre-warming" step to kick off children in the background. Shortly after that, React 19 went final.
SuspenseGate Aftermath and Takeaways ๐︎
In some ways, this whole process was a success. The semi-"broken" behavior was caught prior to release, the concerns were raised to the React team, they listened to the community feedback and delayed the release, and put in the significant amounts of work to implement a better solution. That's great!
But in other ways, this release process, and the communications with the React team, were painfully broken!
The Suspense change was made in March 2023, as React 19 was still in deep development. Looking at the Beta upgrade guide and Beta release notes, the lone mention of the change is a link to the PR under "Other Notable Changes", labeled with the PR title of "Donโt prerender siblings of suspended component". So, technically listed, but certainly not called out with a particular description of what this change was or what the actual impact might be.
Part of this ties into the previously-discussed issues that "Suspense for Data Fetching" was never documented. So, all ecosystem usage was based on the implicit "this is what I see it does in practice" observations, rather than documented behaviors. Talking to Dominik, I think that React Query had a test that rendered a couple sibling components that suspended, but one test with a couple components wasn't going to meaningfully catch that the performance characteristics had changed.
Another issue was that the React team knew this would hurt performance when nesting Suspense-based fetches deeper in the component tree. But, the immediate goal was to make Facebook itself load faster, so that was the obvious focus and intent. On top of that, the PR stated that (paraphrased) "if you really wanted to load data faster, you should be following the best practice of hoisting up to the route/page level instead". That makes some pretty specific assumptions about what kind of apps the React team expects their users to be building (ie, routed CRUD apps with multiple pages).
This is another example of the React team specifically targeting certain kinds of apps with their recommendations and mental model. Even if those kinds of apps are the most common, React usage is far broader than that, and this development process didn't take that into account. Additionally, even if "hoist fetching to the route level" is the most optimal approach architecturally, React itself shouldn't hurt the still-reasonable approach of doing nested Suspense-based fetching.
The second big issue was the speed of release. Yes, the React community had been begging for the release of React 19 for a long time, and pointing out the lengthy delay in stable releases. I can totally understand the desire to get development wrapped up and get the major release out the door.
But in this case, given how widely React is used, jumping from Beta to RC in just a few weeks, and then declaring "this is the final RC barring any major issues" right after that, seems excessively fast. There are millions of React devs in the ecosystem. Tens of thousands of libraries. I know we didn't have time to try testing vs React 19 yet, and I'm sure most other library maintainers and app devs didn't either. The pre-release process felt very rushed. This also would have benefited from additional outreach to both nudge the ecosystem to check, and maybe even assist with those checks somehow.
Finally, this was another example of how communications channels with the React team are sorely lacking.
The drama initially happened on Twitter because Dominik posted a question there and tagged in React team members. That's pretty reasonable, and he had no expectation it was going to go viral. It's also something you'd do quickly - notice a problem, form the question, throw together a tweet and tag a couple people, post it. Unfortunately, once the discussion took on a life of its own, Twitter was a bad place to discuss things in more detail. And, while direct contact with React team members via social media is nice, it also feels inadequate for this sort of "official" discussion topic.
Looking back, the single best set of React team interactions with the community was the React 18 Working Group. The combination of broad-based invitees from the community, direct React team engagement, limited publishing scope, and publicly viewable and searchable discussions, made it a fantastic way to talk through how React 18 would work.
During the "React Community Summit" discussion event, I and several others brainstormed ideas for how we could improve communications between the React team and the community. Our main suggestion was a permanent "React Community Working Group". Reuse that Working Group model, and make that forum the official place to raise concerns and ask questions with the React team. Sure, some discussions could still happen on social media, but rather than ad-hoc tagging of individual team members, post things in a known place where we can guarantee the whole team will see them and that they will try to respond.
Missing Architectural Recommendations ๐︎
There was one more piece of fallout from the "SuspenseGate" discussions. Buried in the Twitter threads (and now deleted), a React team member said:
We never released official Suspense support on the client because it leads client waterfalls. Instead, we shifted into an RSC strategy. I'll let you read between the lines.
Some people got the render-as-you-fetch memo. Some people chose to ignore it.
I don't have the context for the rest of that discussion, but those comments stand out to me as being astonishingly rude and disrespectful (and especially so in contrast to the other explanation of what happened above).
The React team continued to insist that "Suspense for Data Fetching" would come out, eventually. Sure, development plans change - we were originally promised "Concurrent Mode", and instead what we got was "Concurrent Features" as opt-in behavior. But that change actually was explicitly described in the React 18 roadmap post.
In this case, the comment feels like a massive bait-and-switch. After years of promising "Suspense for Data Fetching" on the client, the team says "oh we're not going to do that, and instead you're supposed to do this other completely different architectural approach." This is leaving out entire categories of common usage patterns across the ecosystem, and instead focusing on just the RSC use case. Which, again, can still only meaningfully be used with the Next App Router, leaving anyone not using Next unable to benefit from this, whereas having meaningful Suspense support on the client would enable all React apps to benefit from it.
On top of that, while there were apparently some mentions of "render-as-you-fetch" in the wild, my own awareness and current research says that was limited to the highly experimental / legacy "Suspense for Data Fetching" docs page, possibly used some in relation to the Relay library, and maybe in some social media discussions. As far as I know, it was not ever an official React team recommendation, it certainly wasn't in a prominent location in the legacy docs, and it definitely wasn't in the new docs.
So, nothing was ever officially in the docs about this. Just tweets, maybe some talks at most, an "experimental" docs page that later disappeared... and yet the ecosystem is supposed to have "gotten the memo" that everyone should be using one specific pattern all the time? As another community member put it: "that statement is 10000% historical revisionism".
The "We debated some tradeoffs, missed some usage patterns, will fix it, and get more feedback going forward" response was fantastic. But this comment did not feel like a team that wants to actually support its ecosystem.
The Death of CRA, Recommending Vite, and SPAs ๐︎
Why CRA Broke with React 19 ๐︎
Earlier, I described how Create React App was semi-officially deprecated in early 2023. However, that announcement was via Dan Abramov writing an epic-length comment buried deep in a viral Github issue thread asking to "Switch the docs to recommend Vite instead of CRA". Nothing was ever done to officially deprecate CRA. There was no deprecation of the NPM package, no warnings printed when using the CLI, nothing added to the CRA docs site or React docs saying that you should avoid using CRA going forward, and definitely nothing done to point users to a newer and better alternative build tool like Vite. The only real relevant change was the new React docs setup page dropping all mention of CRA entirely and instead pointing users to "frameworks" like Next and Remix.
React 19 came out in December 2024, and this was a huge release. Many new features, and the removal of long-deprecated React functionality.
However, soon after it came out, I began to see many users posting similar problems across Reddit, the React repo, the CRA repo, and Reactiflux. They all said basically the same thing: "I just tried to create a new React project, and I got an error. What's happening? How do I fix this?"
After investigation, I realized that the release of React 19 broke Create React App. And all of these users were running into the same issue.
CRA has always relied on a pair of project templates for JS and TS. Those templates come with a basic React component structure, and also include several common tools: Jest for unit testing, ESLint for linting, and React Testing Library for testing your components. Unfortunately, the templates hadn't been updated in several years, and were still stuck on old versions of those tools.
The actual problem was a painful crossover between new and old requirements. CRA's CLI always installs the latest version of React automatically, so that the templates didn't have to be updated every time a new React version came out. But, the existing templates were on an old version of React Testing Library that had a peer dependency on React 18. When React 19 came out, running npx create-react-app my-app would try to install the latest React 19 when RTL expected React 18, and this caused a peer dependency version mismatch. The NPM package manager is notoriously inflexible about peer dep mismatches, and would print a long error that translated to "one of your dependencies wanted React 18, you're installing React 19, I can't do that".
Pushing to Fix and Deprecate CRA ๐︎
In theory, no one should be using CRA at this point. It had been unmaintained for at least 3 years, and considered deprecated for 2 years.
But CRA had been recommended for years as the standard React project creation tool for learning and simple SPA projects. There was a very long tail of tutorial videos, articles, and courses that still instructed learners to begin by using CRA to create their first project. Searching for "create a react project" returned old docs pages that recommended CRA. There's also still widespread adoption of CRA within the industry, especially enterprises that moved more slowly. As I described earlier, CRA still sees 12M downloads a month. Yes, those are mostly existing projects and CI builds, but it shows that CRA is far from dead. To make things more difficult, the users who are most likely to be trying to start a new CRA project today are beginners who don't know that they ought to be avoiding CRA, and don't know how to solve a problem like a peer dep mismatch error.
After seeing dozens of the same error reports and answering many of them with "CRA is deprecated, use Vite instead", I started to get frustrated. I care a lot about learners having a good experience, and this was directly blocking many beginners from getting started. It also was a really bad look for the React ecosystem as a whole.
I posted a couple different tweets on Bluesky, both griping and raising awareness about the problem, and tagged several React team members trying to get their attention. The second tweet got a couple responses from the React team, noting that "the 'multi-launcher' approach is still under consideration, but also "I don't have permissions and don't know how to publish it".
The "considering a multi-launcher" response was a useful news update, but it also did absolutely nothing to address the actual issue. That idea had been mentioned 2 years ago, and clearly nothing had been done to move it forward. Beyond that, even if the React team made the immediate decision to push that forward, it would take months of development work and iteration to make that change, when users were facing this breakage right now.
By this time other users had already filed PRs to the CRA repo that would bump the template package versions and fix the actual breakage, as well as PRs to add deprecation notices to the CRA CLI and README. But, it would take someone from the React team with actual permissions to merge and publish them.
A few days later I posted a third tweet on the same topic:
Just saw an article pointing out the same "Create React App is broken" issues I've been highlighting, and also noting it's actually worse - the CRA docs make no mention that it's outdated:
https://www.clientserver.dev/p/create-react-app-is-a-zombie-applicationThis is pretty frustrating to watch :(
https://bsky.app/profile/acemarke.dev/post/3lggg6pk7g22o
And that tweet went viral.
Multiple React team members responded, and the discussion spiraled into extensive subthreads. One comment said "this needs a champion from the team". I agreed, and gave my suggestions on what needed to be done:
If I could magic-wand this:
- Immediate:
- merge + publish template fixes
- update docs to say "deprecated"
- nuke issue spam and archive repo
- follow-up:
- rewrite React "Installation" page to list "SPA" and recommend Vite
- have
craprint deprecation message
In my mind, all of these steps were critical and flowed naturally:
- Fix the immediate breakage, so that users would no longer be blocked and be able to create projects
- Officially mark CRA as deprecated in the docs and the CLI tool, so that anyone creating a project or looking at the docs would now actually know this tool was outdated and shouldn't be used
- Make it clear that CRA was no longer under active development
- Since CRA was deprecated, the right thing to do is to point users to the most similar 1:1 equivalent tool for creating a React project. Vite is absolutely the right answer for that. Pointing CRA users directly to using Vite instead gives them a straightforward path to continue on with creating a project, so that they're not blocked. (And, longer-term, having migration guides to help existing CRA users move away to Vite would help the ecosystem too.)
Debating "Frameworks" and Lack of Vite Recommendation ๐︎
I wrote that "recommend Vite" line knowing it would result in a very negative reaction from the React team. And I was right.
They immediately responded with variations on "No, we're not changing the docs, that seems unrelated". Numerous other community members commented and echoed my points. This devolved into debates of "Vite's React templates don't have a router, which is a minimum viable bar for us to recommend anything", and multiple people including myself asking "look, we've been asking for Vite to be listed for years, why won't you do it?"
That led to the following statement from a React team member:
Iโm not updating it to make it easier to do the bad thing. The people who should build that way, donโt need docs. The people who shouldnโt, donโt need docs.
So no one should need those instructions. The explanation thatโs there is just to placate complaints. But if the placating ainโt placating, maybe we just remove it. Really tired of talking about it.
So apparently "using Vite" / making a standard SPA that is not based on a framework... is "the bad thing". The way that millions of React apps have been built, and are still being built, is "bad". And somehow everyone in the community is supposed to know this and follow this, including beginners who are just getting started.
I pointed out that there's at least 1M projects using Vite + React, and again asked why Vite wasn't listed. The response was "It is listed. Itโs not listed the way you want it to be, but it is there, along with an explanation for why itโs not listed the way you want it to be.".
As I noted earlier: the only mentions of Vite in the React setup docs are the two "you can use Vite" mentions buried in that "Can I Use React Without a Framework?" expandable details section, and the "Add React To An Existing Project" page. Vite is absolutely not listed as a viable option at the top level of the "Start a New Project" page, with the same importance as the other frameworks. Arguing "it's listed" is just wrong.
Actually Fixing CRA ๐︎
At this point I was extremely frustrated, but still wanted to try to address the actual CRA breakage problem, and said "clearly disagree on this, but setting it aside. what can we do to push the rest of the fixes for CRA itself forward?". The response was "go create an umbrella issue with links to PRs/fixes".
So, I wrote up a massive explanation issue titled Umbrella: CRA breaks with React 19, and CRA needs deprecation notices. I described the breakage symptoms, the source of the peer dep mismatches, and linked directly to a couple of existing open PRs to fix the templates and mark the CLI and docs as deprecated. I labeled those as "immediate" solutions.
I also intentionally described my recommendation to update the docs to list Vite as a recommended tool for the "learning and SPAs" use case. Again, knowing that the React team was refusing to listen to my or anyone else on this (and had been refusing to listen for years), but I still felt it was critical as a migration path step.
I also noted in the issue that just doing a basic search for phrases like "create a react project" showed the legacy React docs and the untouched CRA docs as two of the top three hits, which was clearly another issue that would lead beginners astray.
The good news is that after all the drama and arguing over a weekend, the React team did actually listen and take action!. They looked at my umbrella issue, reviewed the linked PRs on Monday, and then merged them and said they had plans to revamp the docs SEO to hide the legacy and CRA docs and point users to the current docs.
This was huge! After multiple years of the community saying "CRA is dead", and the painful arguments and drama of the previous few days, the React team was finally doing something to officially kill off CRA. Absolutely legitimately a wonderfully positive step.
Further Communications Issues ๐︎
Unfortunately, the drama didn't end there.
Over the weekend, there had been a couple mentions of the Bluesky argument threads over on Twitter. Tanner Linsley (creator of React Query and the other TanStack libraries) has been arguing with the React team for years about things like recommending Vite and the emphasis on frameworks. He tweeted:
It's 2025 and the React docs still don't show Vite + vite-react as a 1st class valid target despite an ocean of developers still using CRA for SPAs likely never caring in the slightest what blessed fullstack meta framework is the "idiomatic" way to use react. https://x.com/tannerlinsley/status/1882870735246610758
Another React team member saw this, and left the following reply:
Sigh. We describe using Vite in the docs. We think itโs important for developers to understand the tradeoffs w SPAs vs server-based frameworks. You can disagree about informing devs of tradeoffs (?), or about the prominence of the Vite optionโฆbut itโs very much there.
But your post is going to reinforce an incorrect idea that Vite literally isnโt documented, so now weโll have to correct that FUD, on a weekend. This is really frustrating behavior from a community leader.
This response struck me as a problem on multiple levels:
- Tanner's statement was factually correct. Vite is not listed as "a 1st class valid target", and SPAs are still a widely used architecture in the React ecosystem.
- Arguing that "Vite is described in the docs", as I've said above, is missing the point that Tanner was making.
- The tone is argumentative and scolding, as is the "we'll have to correct that FUD on a weekend" line.
- The phrase "This is really frustrating behavior from a community leader" is shaming, and comes across as trying to prevent someone from expressing an opinion for fear of looking bad. Tanner is very much allowed to state his opinion, where and whenever he wants to. It also misses that many people (including myself) have been giving this exact feedback to the React team for years and it's been repeatedly ignored and rejected. Given that this was both an ongoing current discussion and a recurring frustration, it's not like there was a reason to reach out directly to the React team and say something.
I can understand feeling frustrated after popping online and seeing a topic like this come up yet again, and feeling the need to say something in reply as a thread is taking off. I've had plenty of those moments myself. In this case, I don't think an actual official response was needed. If nothing else, it would really have helped to phrase this differently, maybe along the lines of "We do mention Vite in the docs, but I'll agree it's not as prominent as you'd like. We've stated our reasons for this, but I'd be happy to discuss this in more detail and see if we can find a way to improve this".
Elsewhere in the thread, Theo jumped in and made comments about CRA's SEO being part of the problem, and the React team latched onto that as the one apparent issue with a clear solution.
Reading this, I got frustrated at the combination of miscommunications and missing the larger context of the CRA + Vite discussion, and wrote an extended series of replies. I again pointed out that "Vite is not reasonably listed", linked to another user showing how the docs don't give any clear indication of how to get started as a beginner, and got fed up to the point of saying "the entire React team has been putting their heads in the sand regarding this, and no one understands why you're refusing to listen to feedback". Further down, I said "I've been trying to get this changed for years and have been brushed off with 'we only recommend frameworks'", and finished with a repeated observation that "there's still no good way to have official conversations with the React team, we need a permanent Working Group".
CRA Progress ๐︎
All those frustrations expressed, there is absolutely good news on the CRA front.
As I noted, once I filed the "umbrella" issue, the React team did quickly respond and take action within the next couple days. The template fix and CLI/README deprecation PRs got merged, they're working on docs SEO changes, and trying to work out what other improvements are needed.
So, ultimately, the immediate problem is being fixed, and the ecosystem is going to end up in a better place going forward.
I absolutely understand why the initial breakage didn't come to their attention right away. They'd just shipped React 19, were starting to turn their focus to other new features that had been waiting for React 19 to get out the door, and no one owned CRA at all. I definitely am not assigning blame for that aspect.
But, I do think that this is emblematic of the need for both a dedicated DevRel and a dedicated Working Group venue. I saw the similar issues being posted across the React repo, the CRA repo, Reddit, and Reactiflux. Enough of them got posted that other Redditors were already saying "this is widespread, someone needs to fix this". Ideally, a React team DevRel would have been keeping an eye on community sites like this, noticed it themselves, and escalated internally. Along with that, if there had been a full WG forum, I could have posted it there to raise awareness instead of just posting tweets and tagging team members in the vague-but-unlikely hope that I'd get a response and someone with permissions would do something to fix this.
React Team Outreach and Feedback ๐︎
There is a more positive note after many of these pain points and complaints.
After the debates and arguments around CRA and Vite, a React team lead specifically reached out to me and asked to talk 1:1 so I could give feedback directly. We had a call, and it went very positively. I was very encouraged by the request to be open and give all feedback I wanted to, even if it was about individual team members or incidents. I summarized my main points of concern, and the React lead agreed that those were very understandable reasons to be frustrated and actual issues to be worked on.
They also confirmed the team is actively working on further actions around CRA and trying to consider improvements around messaging and docs, as well as trying to figure out logistics for something like a permanent working group.
Now, I've given plenty of feedback to various team members in various venues over the last few years, and even in cases where they've acknowledged it and said "we're working to improve things", I often haven't seen much visible improvement (or at least not the way I'd hoped for). Still, I absolutely want to give credit for them taking the step to reach out and ask to talk directly with myself and some others, and I do honestly feel they genuinely want to improve communication and interactions going forward. So, I'm hopeful that this will result in positive steps.
Takeaways ๐︎
If you've gotten this far, congratulations and thank you for reading :)
Let me try to sum up the overall points and lessons from all this.
Development Process and Roadmap ๐︎
React's development process inside Meta has been great for letting the React team iterate and polish new features, and the React team has an extraordinarily strong vision for the future of React. However, that's made React into a cathedral-style tool that is hard for anyone outside to contribute to.
As part of that, despite having the code open, there's little clarity or insight into what the React team is working on or why. Roadmap updates are infrequent, and onlookers are often left with having to watch for PRs and inferring what's changing and how the pieces are supposed to fit together.
There's been some good examples of the React team reaching out to ecosystem library maintainers... but also many examples of changes being pushed out too quickly without thinking through the impact those would have on the ecosystem, and in those cases it's been up to library maintainers to deal with the fallout
Frameworks and Architectures ๐︎
The React team does care greatly about app performance, UX, and DX, and they're also sensitive to external complaints that "most React apps load slowly and are too heavy". That has directly driven the push for "frameworks".
React is used in numerous ways. This has always been both a strength and a weakness.
SPAs have historically been a standard way to use React for many reasons (learning, simplicity, architectural constraints), and based on download stats, that's still a widely-used use case for React.
RSCs are a genuinely revolutionary technology and a great addition to React... but they also have a more limited set of use cases, and are not the right tool for every app. They also add complexity and overhead, and the fact that Next is still the only real option for RSCs is a very major problem in terms of perrception and RSC usage. Other frameworks are actively working on RSC support, but based on what I've seen I don't expect any of those to be meaningfully viable options in the near future.
The React team has strongly emphasized focus / support / development on "routed CRUD app"-style apps, particularly with SSR and RSCs. These are probably very common, but that emphasis feels like it ignores other valid forms of React usage.
Overall, the React team needs to do a better job of supporting all the ways that React gets used. The messaging approach of "if you're not using a framework you're doing it wrong" is over-opinionated and exclusionary, and in some ways it's disrespectful.
I see this is the #1 pain point driving community frustration and concerns with the React team today.
Messaging and Communications ๐︎
The React team has a strong vision for React's future and usage... but too strong, to the extent that they have argued with numerous users in the community who have tried to offer suggestions to improve docs or messaging. The switch from "we have no opinions" to the goal of "push React devs towards frameworks so they have better defaults and a chance of better perf" is laudable, but taking a hard stance on this one thing and refusing to listen to feedback asking for tweaks and recognition of broader usage patterns has hurt the relationship with much of the community.
On that note: the community is highly suspicious of the intertwining of development and incentives between Vercel and React. This is understandable, even if overblown or unjustified. "Vercel drives React development to make money off servers" has become a meme at this point and I don't think there's anything the React team can do to directly solve this. However, better docs and changes in overall messaging could maybe make that quiet down over time.
There's also unfortunately been multiple incidents over the years where React team member statements or actions directly showed disrespect for individuals and the community as a whole.
The lack of a dedicated DevRel position has been a consistent problem for years. Adding a DevRel won't magically make communication perfect or change opinions, but it would hopefully be a step in the right direction.
The new React docs are fantastic, but also missing many needed sections: RSC concepts and usage, connecting the fantastic tutorial with real-world project usage, discussions of tradeoffs in React architectures and ways to performance, and more.
The React 18 WG was excellent for communication and direct feedback, but since then there's been no dedicated way for the community to discuss topics and raise concerns with the React team other than social media. There's a desperate need for a permanent React Working Group discussion venue as an official communications channel.
Suggestions ๐︎
When I was growing up, my mom frequently told me "you've stated the problem, now state the solution". As I've said, my goal here is to improve the React ecosystem moving forward. So, let me offer a number of concrete suggestions for things that I think would help communications, learning, and the relationship between the React team and the community. Some are more important than others, but I feel that all of these would have value.
Framework and Build Tool Recommendations ๐︎
As I said above, I think the immovable stance and emphasis on the "FRAMEWORKS!" is the #1 problem with the messaging and interactions from the React team at this time.
I understand their reasoning, and I think they have good reasons to encourage using frameworks. But I also think that the inflexibility here is exclusionary, not sufficiently informative, and does not represent how React is used in the wild.
Given that, I would specifically like to see multiple changes to both the messaging and the docs.
Change Messaging to Match the Breadth of React Usage ๐︎
Big picture, I think the messaging should reflect that React is used in many ways, and that those are all valid ways to use React.
I'm not asking the React team to stop recommending frameworks entirely, or even stop saying "we think frameworks are the best option and here's why".
Conceptually, all I'm asking for is for the messaging and the docs to say "we think a kitchen-sink framework, with routing and data fetching and SSR built in, is the best approach. Here's the main framework options. You can also use React to build a client-only SPA. Here's the main tools for that."
Update React Docs Setup Pages to List Vite and SPAs ๐︎
As a very specific change, I strongly believe the "Start a New React Project" page should explicitly list Single-Page Apps as a valid kind of React project architecture, and specifically point users to Vite as the right tool to use for this.
I'm flexible on what the exact wording ought to be here. If "SPA" is too loaded of a term, some reasonable equivalent is fine. But I honestly think it is critical for this page to be updated to list that category and to specifically name and point to Vite.
Part of this is about the actual instruction itself - users actually reading down that page, seeing "SPA", thinking "that's what I want to build!", and clicking the Vite docs link.
But more than that, it's a very important symbolic acknowledgment that at least half the React community is building SPAs, and that those users are welcomed and encouraged in how they've chosen to use React.
As I wrote in [the CRA "umbrella" issue](), here's my own initial proposal for what that section and wording might look like:
For the "Start a New React Project" page, I would specifically like to see a section added with roughly this phrasing:
Single Page Applications ๐︎
If you are learning React, are not using JS in your backend, only need client-side functionality, or want to design your app configuration yourself, there are other options available for starting a React project.
The most common build tool for this use case is Vite. Since Vite projects do not have opinions, we recommend starting with one of these templates that includes React-based routing libraries with data loading functionality built in:
- Vite + React Router template
- Vite + TanStack Router template
Alternately, you can start from the basic Vite React template and choose your own libraries as needed.
I'm happy to see the exact wording tweaked, but the key points are:
- List Vite specifically as a valid option for starting a React project
- List some of the use cases why it might be a good choice
- Acknowledge that there are many ways to use React, and frameworks are not "one size fits all"
The React team has indicated in recent discussions that "Vite + a data loading router" seem to fit their definition of a suitable "framework", so I'm hopeful that this phrasing would be acceptable.
I could also see a point in more specifically describing a couple other options. The "Add React to an Existing Project" page does a fairly good job of describing the "islands"-style concept of rendering multiple React trees in a server-generated page, but something about the emphasis and instruction here feels off. Beyond that, I'd even consider having a section mentioning tools like React Three Fiber for 3D rendering with React.
I realize that the more options you list, the more confusing it gets. I don't have an absolute solid proposal for exactly all the things that should be listed and exactly how those should be organized. Maybe the "Start a Project" page could be organized more around "How do you want to use React?" and then suggest tools for each use case, sort of Choose-Your-Own-Adventure style, rather than immediately jumping into "YOU SHOULD USE FRAMEWORKS!". That's all TBD.
Overall I'm much more interested in seeing some change here, than the specifics of that change.
- Docs:
- Rework the "New Project" page to 1) list SPAs as a valid React usage option, 2) recommend Vite for "learning and SPAs". (Also replace Gatsby with Astro or something.)
- Document RSC core concepts, architecture, and tradeoffs
- Add a section to the tutorial that lists next steps and connects "writing a component in a sandbox" to real-world usage
- Move the CRA docs to a
legacy.create-react-app.devsubdomain. Replace them with a new set of docs that has guidance for setting up a new project with Vite or Next, and migration guides to move away from CRA (or at least point to migration guides) - Specifically direct CRA users to use Vite instead as the most 1:1 equivalent tool, including in the CLI deprecation message
- Invest time in writing articles with detailed discussions of architectural patterns that lead to good React performance and why they matter (SSR, hoisting fetching to the route level, code splitting, etc), rather than just saying "use a framework". Also give advice on how to do that even in a client-side SPA.
- Communications:
- Deprecate the RFC repo? not sure it's doing much good at this point
- Actually stand up a formal and permanent React Working Group repo. Same "broad invitee" model as React 18 WG. Make it the official way to raise concerns, and have the team actually read and respond to those discussions.
- Stop coming down on members of the community for daring to express opinions that don't exactly match yours, or insulting users who are doing admittedly hacky things to work around limitations in React that you've never taken the time to address
- Post monthly updates on the blog about "what we've been doing"
- Add some kind of "TC39 stages"-style description of WIP features.
- Actually have a full-time DevRel (or multiple) consistently interacting with the community, answering questions, dealing with concerns
- Acknowledge that React is used in a broad variety of ways, and act like you actually want to support your whole community, not just people using RSCs with Next
TODO ๐︎
- mention my "React Community Tools" site
- SvelteKit mentions "use Vite": https://bsky.app/profile/thiagolino8.bsky.social/post/3lgnzpa42e22l
- thoughts on the
react-three-fiberteam - shared this with other community members and had widespread agreement
This is a post in the React and the Community in 2025 series. Other posts in this series:
- Feb 10, 2025 - React and the Community in 2025, Part 2: React Team Interactions with the Community
- Feb 10, 2025 - React and the Community in 2025, Part 1: Development History and Clarifying Community Concerns