Library / SDK
ReactiveX/rxjs avatar
ReactiveX/rxjs

RxJS 9: a platform-native rewrite, and why the npm next tag will not get you there

A reactive programming library for JavaScript

31,705 stars2,984 forksTypeScriptApache-2.0

At a glance

What is it?
The ReactiveX/rxjs master branch is now the RxJS 9 line, which builds on the native web-platform Observable and ships ESM only. RxJS 7 remains the production release, and the beta is not on npm yet.
Who is it for?
Adopt RxJS 9 only if you are prototyping against master or tracking the Web Platform Observable proposal, and install it from a checkout rather than npm. Stay on RxJS 7 for production Angular or Node work until 9.0.0-beta.0 is published.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 52 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

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

Editorial analysis

What RxJS 9 changes for anyone importing from rxjs

RxJS is a library for composing asynchronous and event-based programs with Observable values. That description has not changed. What changed is the foundation under it. The version on master is described in the README as "the platform-based next generation of RxJS, planned for release as RxJS 9," and the repository states plainly that it is prerelease work in development. The audience is narrow: engineers who already know Observables and want to see where the library is heading, plus anyone building against the Web Platform Observable proposal and needing a conforming fallback. If you are looking for the version to put in a production Angular app today, this is not it. RxJS 7 is the production latest line and, per the README, continues to be maintained. RxJS 9 is a different contract with a different import style, and the two are not drop-in compatible.

Why the version jumped from 7 to 9, and what RxJS 8 was

The README addresses this directly because the numbering looks like a mistake. RxJS 8 was real work. Development began years ago and was paused while the Web Platform Observable proposal was finalized. The team then chose to restart on a platform-based implementation rather than continue the paused branch. Bumping to 9 is a deliberate signal: the README says it makes "the architectural break unmistakable and avoid presenting the old RxJS 8 work as the released product." That is an honest call, and it has a cost. Anyone who tracked RxJS 8 prereleases has a branch that will never ship under that number. The npm next tag still points to the earlier RxJS 8 prerelease, which is why the README warns against using it to install RxJS 9. Two prerelease lines exist, only one of them is the future, and the tag does not distinguish them.

The mechanism: native Observable, Symbol-keyed operators, AbortSignal

Three design decisions define the architecture. First, RxJS uses the native web-platform Observable when one exists and installs a conforming fallback only when needed. The fallback lives in a separate package, @rxjs/observable-polyfill, so environments that already have the platform type do not pull in a duplicate implementation. Second, operators and factories are exact, module-owned Symbols rather than string-named methods. The README is explicit that they "do not add string-named RxJS methods to the platform API." The consequence is visible in the syntax: you import the operator and call it with bracket notation, so observable[map](project) is the RxJS contract while observable.map(project) stays the platform contract. Those are separately versioned, which means a platform method and an RxJS operator with the same name can coexist without one silently shadowing the other. Third, cancellation is built on AbortSignal and the platform Subscriber lifecycle. Producer behavior is also split into explicit contracts: the README says to use ColdObservable when each direct subscription must create its own producer. That is a meaningful distinction rather than a naming preference, because it forces the producer-per-subscription decision into the code instead of leaving it implied. Published JavaScript is ESM-only; the README notes that current Node can bridge require() to the same ESM files, so there is no duplicate CommonJS build to keep in sync.

Installing RxJS 9 today, and a first program

There is no npm install path for RxJS 9 right now. The README states that the planned first beta is 9.0.0-beta.0 but "has not been published to npm yet," and it warns not to use npm's next tag, which still resolves to the RxJS 8 prerelease. So the only way to run the preview is from a checkout of the repository. The contribution section gives the toolchain: Node 22.13+ and pnpm 10.34.5, with commands run from the repository root. The first block installs dependencies and runs the package's Vitest suite against src.

sh
pnpm install
pnpm --filter rxjs exec vitest --run src
pnpm --filter rxjs run test:package

The second block is the planned beta API as the README presents it. Note the import of the operator from its own module path, and the bracket call.

ts
import { ColdObservable } from 'rxjs';
import { map } from 'rxjs/map';

const source = new ColdObservable<number>((subscriber) => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.complete();
});

source[map]((value) => value * 2).subscribe(console.log);

Running that against the current source should log 2 and 4. If you are wiring the polyfill instead, the package is @rxjs/observable-polyfill, and the repository exposes its lifecycle tests through pnpm run test:lifecycle at the root. For migration work there is @rxjs/migrate, described as a deterministic migration engine, and @rxjs/test for virtual-time and marble testing. Treat all four as prerelease packages with no published npm artifact.

The limitation that matters: RxJS 9 is not installable and not the maintained line

The most concrete constraint is publication. A library that cannot be installed from npm cannot be adopted, only studied. The repository's own release gates and secure release runbook exist because publication is treated as irreversible, and until that runbook has been executed for 9.0.0-beta.0, every consumer is building from source. The second constraint is environment. The planned beta supports Node 22.13+ and Node 24 as blocking lanes, with Node 26 advisory, and the root package.json sets engines.node to >=22.13.0. Teams on Node 18 or 20 are outside the supported set. The third is the compatibility posture. The README says the complete source-pinned RxJS 7 corpus "intentionally retains reviewed lifecycle and compatibility divergences, so it is migration evidence rather than a blanket RxJS 9 compatibility gate." Read that carefully: passing the RxJS 7 test corpus is not a promise that your RxJS 7 code behaves identically. ESM-only output is a fourth constraint. If your build chain still emits or consumes CommonJS as a first-class target, the README's note about Node bridging require() to ESM covers Node, not an arbitrary bundler configuration. And if you are on Angular, the framework's own dependency on RxJS 7 is outside this repository's control; nothing here says Angular has moved.

Alternatives, and where the difference actually lies

The obvious alternative is staying on RxJS 7, which the README describes as the production latest line that continues to be maintained. The difference is not feature count, it is the contract. RxJS 7 exposes string-named operators as methods on its own Observable class and ships both CommonJS and ESM builds. RxJS 9 delegates the Observable type to the platform, keys operators by Symbol, and ships ESM only. If your code calls source.pipe(map(...)) against the RxJS 7 import, that is a different API surface from source[map](...) against the RxJS 9 one. A second alternative is to consume the platform Observable directly and skip the operator library entirely. That is a legitimate choice for simple cases, and RxJS 9's architecture is designed to make it cheap: the polyfill is conditional, so an environment with a native Observable pays nothing for it. What you give up is the operator set. The moment you need marble testing, virtual time, or a migration path from existing RxJS code, the packages in this repository are the reason to be here rather than on the raw platform type.

Maintenance, release gates and the Apache 2.0 licence

The last push to master was on 2026-08-08, and the repository is not archived. The most recent release listed is 9.0.0-beta.0 dated 2026-08-04; the two entries before it are 8.0.0-alpha.14 from 2024-01-12 and 8.0.0-alpha.13 from 2023-12-20. That gap is the visible cost of the paused RxJS 8 line, and it is worth weighing if you are deciding whether the 9 line will move quickly. The repository documents its own release discipline: release support and exact environment gates live in packages/rxjs/docs/RELEASE_GATES.md, the publication process in docs/RELEASE_PROCESS.md, and a security-assurance document covering release evidence, verification commands, a sole-maintainer model and an OpenSSF Scorecard. A sole-maintainer model is a real continuity risk for a library this widely depended on, and the repository names it rather than hiding it. The root package.json declares Apache-2.0, matching the LICENSE.txt at the top level. Apache 2.0 is permissive and includes an explicit patent grant, which matters for a library that implements a platform proposal. This is a description of the licence file, not legal advice; if patent terms or attribution obligations affect your organisation, have counsel read LICENSE.txt.

Editorial conclusion

Adopt RxJS 9 only if you are prototyping against master or tracking the Web Platform Observable proposal, and install it from a checkout rather than npm. Stay on RxJS 7 for production Angular or Node work until 9.0.0-beta.0 is published. Before committing, verify the beta's npm publication status, the Node 22.13+ engine gate, and whether your bundler resolves Symbol-keyed operator imports such as rxjs/map.

Frequently asked questions

What does RxJS stand for?

The repository is ReactiveX/rxjs, and the README describes RxJS as a library for composing asynchronous and event-based programs with Observable values. The name is the JavaScript member of the ReactiveX family.

What does reactive programming mean?

The README frames it as composing asynchronous and event-based programs with Observable values. In RxJS 9 that composition is expressed through Symbol-keyed operators called with bracket syntax, and cancellation runs on AbortSignal and the platform Subscriber lifecycle.

Can I use RxJS with react?

The README does not document React integration. Its supported-environment list names Node 22.13+, Node 24, current Chrome, Firefox, desktop and Mobile Safari, Deno, Bun and Webpack 5, and says nothing about React.

What is RxJS and what is its purpose in Angular?

The README says RxJS 7 remains the production latest line and continues to be maintained, while master carries the prerelease RxJS 9 work. The repository does not describe Angular integration, so it does not state which line Angular depends on.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. ReactiveX/rxjs on GitHub
  4. README
  5. Releases
Add this badge to your README

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

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/reactivex-rxjs.svg)](https://hysenlabs.com/projects/reactivex-rxjs)