RxJS: What’s Changed with shareReplay?

Photo by Namroud Gorguis on Unsplash

In RxJS version 6.4.0, a change was made to the operator. Let’s look at why the operator needed to be changed, what was changed and how the change can be used to avoid surprises — and bugs.

If you’re only interested in the change, skip to the TL;DR at the bottom of the article.

The operator’s history

The operator was introduced in version 5.4.0.

Like the operator, returns a hot, reference-counted observable, but replays the specified number of notifications. Also, if the source completes, it ensures that the notification is replayed to new subscribers and that no further subscriptions are made to the source observable.

In the version 5.4.0 implementation of , when the subscriber reference count dropped to zero — without the source having completed — the operator would unsubscribe from the source. Subsequent resubscription to the shared observable would increment the reference count from zero to one, effecting a resubscription to the source using a newly-created .

Let’s look at an example:

As written, this example won’t work with RxJS version 5.4.0 because pipeable operators were not introduced until version 5.5.0. However, the example is written as it would be in version 6, so that it’s easier to understand.

Also, all of this article’s examples use the following helper function. It wraps an observable, gives it a name and logs to the console whenever a subscriber subscribes or unsubscribes, or the observable nexts or completes:

The example program subscribes to a shared source observable that uses a to emit a value 100 milliseconds after subscription:

  • the first subscription is made immediately, but is unsubscribed —via — before the source emits a value; and
  • the second subscription is made 150 milliseconds after the first and is not unsubscribed.

The program’s output is:

Looking at the output it’s clear that two subscriptions are made to the source observable. The unsubscription of the first subscriber to the shared observable effects an unsubscription from the source — because the reference count drops to zero — so when the second subscription to the shared observable is made, the implementation needs to subscribe to the source again.

In some situations that behaviour might not be what you want.

For example, if the source effects a HTTP request, you might not want that request to be cancelled. You might want the request to complete, so that the response can be stored in the shared observable — ready for the next subscriber.

In version 5.5.0-beta.4, a ‘bug’ was fixed and the behaviour of the operator was changed so that the subscription to the source was not unsubscribed when the reference count dropped to zero.

The example program’s output with version 5.5.0-beta.4 is:

Here, only one subscription is made to the source observable. The unsubscription of the first subscriber to the shared observable does not effect an unsubscription from the source. The within the implementation of remains subscribed to the source observable — which allows the source to complete and the to store the and notifications.

Unfortunately, by changing to better support the use case in which a source emits once — and then completes — the use case in which a source emits multiple times — without completing — breaks, as the operator’s remains permanently subscribed to the source.

Let’s look at an example that uses an instead of a :

Here a subscription is made to the source and is then unsubscribed — via — a short while after the source emits its first value.

The program’s output is:

Because the source observable does not complete, it is never unsubscribed — despite there being no subscribers to the shared observable. So the source observable continues to emit values.


In version 6.4.0, a change was made so that both use cases could be supported.

The change — TL;DR

The essential difference between the version 5.4.0 and 5.5.0-beta.4 implementations of was that the earlier version implemented reference counting and the later version disabled it.

To allow for both of the use cases that we’ve look at, an additional parameter was added to .

The operator already had three parameters — all of which were optional — so, to avoid making things event more complicated, an additional overload signature that takes a single config parameter was added. The config interface and signature look like this:

Using the config parameter, the example that uses an as the source can be rewritten to behave correctly:

With enabled, the source will be unsubscribed when the reference count drops to zero and the source will no longer emit forever:

Avoiding surprises

The property in the config parameter is deliberately not optional.

To avoid any potential confusion — due to the differing implementations of between RxJS versions — I would recommend always using the signature that takes the config parameter. That way, it’ll be clear whether or not the reference counting behaviour is or isn’t wanted.

I’ve added an option to the rule in to allow to be used if the config parameter is specified. The rule’s configuration looks like this:

If is an operator that you use in your apps, you might want to make sure that it’s behaving appropriately for your use case. And you might want to switch to passing a config argument.

This post is also published on my personal blog: ncjamieson.com.

RxJS core team member; front-end developer; mentor; speaker; open-source contributor

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store