# What Is the $$observable Symbol in Redux? TC39 Observable Interop Explained

> Understand the $$observable symbol in Redux. Learn how this TC39 Observable interop enables libraries like RxJS to integrate seamlessly with your Redux store.

- Repository: [Redux/redux](https://github.com/reduxjs/redux)
- Tags: deep-dive
- Published: 2026-03-05

---

**The `$$observable` symbol in Redux serves as the interoperability point for the TC39 Observable proposal, allowing libraries like RxJS to treat the Redux store as a reactive stream using `store[$$observable]()`.**

The `reduxjs/redux` library implements the `$$observable` symbol to provide a standardized mechanism for reactive programming libraries to subscribe to state changes without coupling Redux to any specific observable implementation. This lightweight interop point enables powerful stream-based state management while maintaining a minimal core bundle size.

## Defining the $$observable Symbol in Redux Source Code

The symbol is defined in [`src/utils/symbol-observable.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/symbol-observable.ts) as a cross-environment compatible identifier:

```ts
// src/utils/symbol-observable.ts
const $$observable = /* #__PURE__ */ (() =>
  (typeof Symbol === 'function' && Symbol.observable) || '@@observable')()
export default $$observable

```

This implementation checks for the native `Symbol.observable` defined by the TC39 proposal. If available, it uses that; otherwise, it falls back to the string `"@@observable"`. This approach guarantees a **stable, collision-free property name** that any reactive library can reference consistently across different JavaScript environments.

## How $$observable Exposes the Store as an Observable

In [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), the store factory attaches the observable implementation using the `$$observable` computed property key:

```ts
// src/createStore.ts (excerpt)
const store = {
  dispatch,
  subscribe,
  getState,
  replaceReducer,
  [$$observable]: observable   // <‑‑ the interop point
}

```

The `observable()` function closes over the store's `subscribe` method and returns an object implementing the **minimal observable contract**:

```ts
// src/createStore.ts (excerpt)
function observable() {
  const outerSubscribe = subscribe
  return {
    subscribe(observer) { … },
    [$$observable]() {
      return this
    }
  }
}

```

The returned object provides a `subscribe` method that accepts an observer object with a `next` callback, and a self-referencing `[$$observable]()` method that returns the observable instance. This minimal implementation satisfies the interop requirements of libraries like **RxJS**, **most.js**, and **Bacon.js** while keeping Redux independent of any reactive library dependencies.

## Practical Usage: Converting Redux Store to RxJS Streams

### Accessing the Minimal Observable Directly

You can obtain the raw observable from the store to subscribe to state changes:

```ts
import { createStore } from 'redux'
import rootReducer from './reducers'
import $$observable from './utils/symbol-observable'   // internal symbol

const store = createStore(rootReducer)

// Obtain the minimal observable via the interop point
const observable = store[$$observable]()

// Subscribe using the observable API
const subscription = observable.subscribe({
  next(state) {
    console.log('New state via observable:', state)
  },
})

// Later – unsubscribe
subscription.unsubscribe()

```

### Using RxJS `from()` to Create a Full Observable

RxJS automatically recognizes the `$$observable` property and converts the store into a full-featured observable:

```ts
import { from } from 'rxjs'
import { distinctUntilChanged, map } from 'rxjs/operators'
import { createStore } from 'redux'
import rootReducer from './reducers'

const store = createStore(rootReducer)

// `from` recognises the $$observable interop point
const redux$ = from(store)

// Now you can use all RxJS operators
redux$
  .pipe(
    map(state => state.todos),
    distinctUntilChanged()
  )
  .subscribe(todos => console.log('Todos from RxJS:', todos))

```

### Verifying Fallback Behavior in Older Environments

The symbol utility ensures compatibility when `Symbol.observable` is undefined:

```ts
// Force the fallback path (e.g., in older browsers)
console.assert(typeof Symbol.observable === 'undefined')
console.assert($$observable === '@@observable')

```

## Summary

- The `$$observable` symbol provides the **TC39 Observable proposal** interop point in `reduxjs/redux`
- Defined in [`src/utils/symbol-observable.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/symbol-observable.ts), it uses `Symbol.observable` when available or falls back to `"@@observable"` for maximum compatibility
- The store exposes a minimal observable implementation via `store[$$observable]()` in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), using the store's internal `subscribe` method
- The TypeScript declarations in [`src/types/store.ts`](https://github.com/reduxjs/redux/blob/main/src/types/store.ts) ensure type safety for the observable property
- Libraries like **RxJS** can convert Redux stores to full observables using `from(store)` without adding dependencies to the Redux core

## Frequently Asked Questions

### What is the purpose of the $$observable symbol in Redux?

The `$$observable` symbol serves as a well-known interoperability point that allows the Redux store to be treated as an observable by reactive libraries. According to the `reduxjs/redux` source code in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), it exposes a minimal observable implementation via `store[$$observable]()`, enabling subscription to state changes through the standard observer contract without bundling RxJS or similar libraries into Redux itself.

### How do I use Redux with RxJS?

You can convert a Redux store to an RxJS observable by importing `from` from RxJS and passing the store directly: `const store$ = from(reduxStore)`. RxJS detects the `$$observable` property defined in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) and wraps the store's minimal observable implementation, allowing you to use operators like `map`, `filter`, and `distinctUntilChanged` on the state stream.

### What happens if Symbol.observable is not available?

If the JavaScript environment does not define `Symbol.observable`, Redux falls back to the string `"@@observable"` as implemented in [`src/utils/symbol-observable.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/symbol-observable.ts). This polyfill approach ensures the observable interop works in older browsers or environments that haven't implemented the TC39 proposal, maintaining compatibility across Node.js and legacy browser contexts.

### Is the $$observable API stable for production use?

Yes, the `$$observable` implementation in Redux is stable and battle-tested. The [`test/createStore.spec.ts`](https://github.com/reduxjs/redux/blob/main/test/createStore.spec.ts) file in the `reduxjs/redux` repository contains comprehensive tests verifying the observable interop behavior, including the `subscribe` method and the self-referencing symbol property. The API follows the TC39 Observable proposal specification, making it safe to use in production applications requiring reactive state management integration.