# RxSwift: the Observable abstraction for Swift, and what Combine changed

> RxSwift is the Swift implementation of the ReactiveX standard, split into five modules with RxSwift at the base. Its 6.10 line dropped CocoaPods and fixed how AsyncSequence bridging inherits actor context.

**ReactiveX/RxSwift** — Reactive Programming in Swift

- Repository: https://github.com/ReactiveX/RxSwift
- Stars: 24,632 · Forks: 4,150
- Language: Swift
- License: MIT
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/reactivex-rxswift

## One abstraction over KVO, async work and UI events

The README states the goal without much ornamentation: Rx is a generic abstraction of computation expressed through the `Observable<Element>` interface, which lets you broadcast and subscribe to values and other events. RxSwift is the Swift-specific implementation of the Reactive Extensions standard.

The practical claim is unification. KVO observation, asynchronous operations and UI events are all expressed as the same abstraction of sequence, so a value arriving from a key path change, from a network call and from a tap gesture can be composed with the same operators. That is the entire argument for the library, and it is either sufficient or it is not.

The README also sets an expectation about the API shape: this version aims to stay true to the original spirit and naming conventions of Rx while also providing a Swift-first API. So you will recognise the operator names from other ReactiveX ports, and you will also meet Swift conveniences that the original standard does not have.

Platform coverage is broader than the badge suggests at a glance. The supported platforms line lists iOS, macOS, tvOS, watchOS and Linux, which matters for anyone sharing a data layer between an app and a server-side component.

## Five modules with a dependency order worth respecting

The README includes an ASCII diagram of how the pieces relate, which is more useful than it looks because the dependency order is the thing people get wrong when they import something convenient from the wrong module.

`RxSwift` is the core, providing the Rx standard as mostly defined by ReactiveX, and it has no other dependencies. `RxCocoa` sits on top and adds the Cocoa-specific capabilities for general app development, shared sequences and traits; it depends on both `RxSwift` and `RxRelay`. `RxRelay` provides `PublishRelay`, `BehaviorRelay` and `ReplayRelay`, described as simple wrappers around Subjects. `RxTest` and `RxBlocking` provide testing capability and depend on `RxSwift`.

So the shape is a two-level stack: RxSwift at the base, with RxCocoa and RxRelay as optional application-level additions, and RxTest and RxBlocking as the testing branch. RxSwift alone is usable, which matters if you are writing a non-UI component.

The traits are the other structural idea you need before the code makes sense. `Single`, `Completable`, `Maybe`, `Driver` and `ControlProperty` each exist because a plain `Observable` cannot express the intent: some of them carry a success value, some carry only completion, some are designed for main-thread UI binding. The README has a dedicated document for them, and reading it before writing code is the difference between using RxSwift and fighting it.

## The search example as the shape of real usage

The README's worked example is a GitHub repository search bound to a table view, and it is worth reading slowly because it demonstrates the idiom rather than the API surface. The pipeline starts from the search bar's text and immediately shapes the stream before any network work happens:

```swift
let searchResults = searchBar.rx.text.orEmpty
    .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
    .distinctUntilChanged()
```

`throttle` with a 300 millisecond window stops a keystroke from triggering a request per character, and `distinctUntilChanged` drops repeats, which matters because typing and deleting the same character produces the same string. `MainScheduler.instance` is where that work runs, which is the first place the library makes you think about threads.

The second half is where the stream meets the UI, and it ends with a disposal bag:

```swift
searchResults
    .bind(to: tableView.rx.items(cellIdentifier: "Cell")) {
        (index, repository: Repository, cell) in
        cell.textLabel?.text = repository.name
        cell.detailTextLabel?.text = repository.url
    }
    .disposed(by: disposeBag)
```

That last line is the whole lifecycle story in one method call. There is no explicit unsubscribe anywhere, because the subscription ends when the bag that holds it is deallocated. `bind(to:)` also fixes the thread for the UI work, which is why the pipeline does not need a separate observe-on at the end.

## Version 6.10 dropped CocoaPods and changed async bridging

Three releases in early 2026 tell the same story, and they contain a versioning oddity worth noticing. 6.10.0 was published on 2026-01-22, 6.10.1 on 2026-01-27, and 6.10.2 on 2026-03-02. The 6.10.1 notes describe themselves as identical to 6.10.1 Kawazoi aside from manifest fixes, and 6.10.2 says it is identical to 6.10.1 / 6.10 Kawazoi aside from Mac Catalyst support and Swift 5.9 manifest issues. So three different version strings and a release codename refer to substantially the same content.

That is not a blocker, but it means you cannot infer what changed from the patch number alone. Read the release notes rather than trusting the version arithmetic.

The substantive breaking change is shared by all three: CocoaPods support has been officially deprecated, following CocoaPods' read-only trunk notice, with a direct request to migrate to Swift Package Manager or Carthage. If your app integrates RxSwift through a Podfile, this is a migration you now have to plan rather than a deprecation you can defer.

The second breaking change is a small one with real consequences. `AsyncSequence.asObservable()` now uses `Task.detached` instead of `Task`, so iteration no longer inherits the calling task's actor context. The release notes describe the removed hazard precisely: iteration could unexpectedly inherit actor context, causing deadlocks or unexpected serialization. You can also pass a `TaskPriority` optionally. If your code bridges async sequences into Rx and does not use detach, you have a latent deadlock to look for.

## Installation, packaging and where the documentation lives

The README's installation section states one thing plainly: RxSwift doesn't contain any external dependencies. The packaging story is visible in the repository rather than in the prose. There is a `Package.swift` and a separate `Package@swift-5.9.swift`, so the package declares version-specific manifests, and both Swift Package Manager and Carthage badges are shown. There is also `Rx.xcodeproj/` and `Rx.xcworkspace/` for the Xcode route, plus `Package.swift` alongside `Rx.playground/` for working through operators interactively.

The documentation is a directory rather than a website, which suits a library whose API reference is generated. `Documentation/` holds the documents the README links: Why.md, GettingStarted.md, Traits.md, UnitTests.md, Tips.md, MathBehindRx.md, HotAndColdObservables.md, Subjects.md, ComparisonWithOtherLibraries.md and ExampleApp.md. The comparison document is the one to read first if you are weighing RxSwift against Combine or ReactiveSwift, since that is the decision the README cannot make for you.

Tooling is mise-based. There is a `mise.toml`, a `.swift-version` file, `.swiftlint.yml`, `.swiftformat` and a `Dangerfile`, and the whole `Makefile` is a single format target running `mise x swiftformat -- swiftformat .`. The CI badge points at a `tests.yml` workflow, with `Tests/` and `Sources/` directories at the root. The licence is MIT in `LICENSE.md`, and the last push to the repository was on 2026-09-04.

## Conclusion

RxSwift is still the right choice for a codebase that already uses it, for cross-platform targets including Linux, and for teams that want one operator vocabulary across Combine and Swift concurrency. It is a weaker choice for a new SwiftUI-only app, where `AsyncSequence` and the async/await ecosystem already cover much of the same ground without a second abstraction. Check three things before you commit: that CocoaPods is gone from your dependency list, given the 6.10 deprecation, that your async bridging passes through `AsyncSequence.asObservable()` knowing it now runs detached, and that the traits you need exist, since `Single`, `Completable`, `Maybe`, `Driver` and `ControlProperty` carry semantics plain `Observable` does not. Start with `Documentation/GettingStarted.md` and the comparison document before writing a view model.

## FAQ

### What are RxSwift's main modules?

Five, with a fixed dependency order. `RxSwift` is the dependency-free core, `RxRelay` provides PublishRelay, BehaviorRelay and ReplayRelay as wrappers around Subjects, `RxCocoa` adds the application-level layer and depends on both, and `RxTest` plus `RxBlocking` provide the testing capability.

### How do I use observables in Swift?

RxSwift exposes them through the `Observable<Element>` interface, where you compose streams with operators and subscribe to the result. The README's example starts from `searchBar.rx.text.orEmpty`, applies `throttle` and `distinctUntilChanged`, and ends by binding to a table view with `.disposed(by: disposeBag)` so the subscription ends with the bag's lifetime.

### Is CocoaPods still supported by RxSwift?

No. Version 6.10 officially deprecated CocoaPods support, following CocoaPods' read-only trunk notice, and the release notes ask users to migrate to Swift Package Manager or Carthage. The repository carries both a `Package.swift` and a `Package@swift-5.9.swift` for that path.

### When should I choose RxSwift over Combine?

Two documented reasons favour RxSwift: it covers Linux as well as iOS, macOS, tvOS and watchOS, and it has a much larger third-party surface. Apple's own comparison document in the repository's Documentation directory is the place to check current positioning, since the ecosystem has changed since Combine shipped.

### What changed in RxSwift 6.10?

Two breaking changes: CocoaPods support was deprecated in favour of Swift Package Manager and Carthage, and `AsyncSequence.asObservable()` switched from `Task` to `Task.detached` so iteration no longer inherits the calling task's actor context, removing a potential deadlock. Follow-up 6.10.1 and 6.10.2 releases fixed manifests and Mac Catalyst support.

## Sources

- [Issues](https://github.com/ReactiveX/RxSwift/issues)
- [License: MIT](https://github.com/ReactiveX/RxSwift/blob/main/LICENSE)
- [ReactiveX/RxSwift on GitHub](https://github.com/ReactiveX/RxSwift)
- [README](https://github.com/ReactiveX/RxSwift/blob/main/README.md)
- [Releases](https://github.com/ReactiveX/RxSwift/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/reactivex-rxswift
