Open-source project
ReactiveX/RxSwift avatar
ReactiveX/RxSwift

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

Reactive Programming in Swift

24,632 stars4,150 forksSwiftMIT

At a glance

What is it?
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.
Who is it for?
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.
Can I use it commercially?
Yes. MIT 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 37 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

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

Editorial analysis

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 `[email protected]`, 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.

Editorial 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.

Frequently asked questions

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 `[email protected]` 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.

Official sources

  1. Issues
  2. License: MIT
  3. ReactiveX/RxSwift 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-rxswift.svg)](https://hysenlabs.com/projects/reactivex-rxswift)