Library / SDK
pointfreeco/swift-composable-architecture avatar
pointfreeco/swift-composable-architecture

The Composable Architecture: a reducer-based state layer for SwiftUI and UIKit

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.

14,940 stars1,679 forksSwiftMIT

At a glance

What is it?
TCA is an MIT-licensed Swift package that models features as State, Action, Reducer and Store, with first-class testability. It suits teams that want one pattern across iOS, macOS, tvOS, watchOS and visionOS, and it costs you a learning curve before it pays anything back.
Who is it for?
Adopt TCA if you have more than one screen sharing state, a test suite you intend to keep honest, and at least one engineer willing to learn the reducer model before the first feature ships. Do not adopt it for a single-view app, a throwaway prototype, or a team that cannot absorb a new mental model on top of SwiftUI.
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 12 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 September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem TCA solves: state that outlives one screen

Most SwiftUI apps start with @State in a view and stay coherent until two screens need the same value. At that point state gets pushed into an environment object or a singleton, mutation happens from several places, and the ordering of those mutations becomes impossible to reason about. The Composable Architecture answers that with a single rule: state changes only inside a reducer, and only in response to an action. The README frames the library around five concerns, listing state management, composition, side effects, testing and ergonomics. The target audience is Apple-platform developers building something large enough that the cost of an explicit model is lower than the cost of debugging implicit one. It is not a UI framework. It sits underneath SwiftUI, UIKit, or anything else that can read a value and send an action.

State, Action, Reducer, Store: the four moving parts

A feature is a type annotated with the @Reducer macro. Inside it you declare State, marked with @ObservableState so views can observe it through the library's observation tools, and an Action enum covering everything that can happen, from a button tap to a timer firing. The reducer itself is a function that takes the current state and an action and returns the next state, plus an optional Effect for work that touches the outside world, such as a network request. The Store is the runtime: you send actions into it, it runs the reducer, executes any effect, and feeds the resulting actions back in. Views read state from the store and send actions to it. That loop is the whole architecture. Composition happens because a parent reducer can embed a child reducer and map its actions, so a large feature is a tree of small features, each of which can live in its own module. The repository layout reflects that: Sources/ holds the library, Tests/ holds its tests, and Examples/ holds runnable apps including CaseStudies, Search, SyncUps, TicTacToe, Todos and VoiceMemos.

Installing the package and writing your first reducer

The README points at the Installation section for setup and the documentation link for reference material. The package is consumed as a Swift Package, so in Xcode you add it through File, Add Package Dependencies and point at the repository, or you declare it in a Package.swift manifest. The dependency product is named ComposableArchitecture. Once it resolves, import it in the file that defines your feature.

swift
import ComposableArchitecture

@Reducer
struct Feature {
}

The README's own starting point is exactly this: a struct annotated with @Reducer. That alone compiles and does nothing. The next step is the state, which in the README's counter example is an integer plus an optional string for a fetched fact.

swift
@Reducer
struct Feature {
  @ObservableState
  struct State: Equatable {
    var count = 0
    var numberFact: String?
  }
}

The @ObservableState macro is what lets a view observe mutations without you writing an ObservableObject. Note that State conforms to Equatable, which is what makes state comparison possible in tests. From here the README continues with an Action enum for the increment and decrement taps and the fact-fetching button, and a reducer body that returns effects for the API call. The repository also ships a Makefile with targets for building and testing the library itself, including a format target that runs xcrun swift-format over the Swift sources, which is useful if you want to match the project's own style in a fork.

Where TCA is the wrong tool

The reducer model is a tax you pay up front. Every new screen needs a State type, an Action enum, a reducer body and a store, and for a view that displays a label and a button that tax buys nothing. The README itself notes that the library is for applications of varying purpose and complexity, but the examples it ships are not trivial. If your app is a single form or a settings screen, plain SwiftUI state is shorter and easier to hand to the next developer. There is also a versioning hazard visible in the release list: 1.23.3 was published on 2026-09-18, after 1.26.2 on 2026-08-28 and 1.26.1 on 2026-07-21. That ordering suggests a maintenance branch cut for an older line rather than a straight progression, so pinning a version by number alone is not enough; check which line the tag belongs to. Finally, the repository contains a [email protected] alongside Package.swift, which means toolchain requirements differ between manifests. Teams on older Xcode versions should confirm compatibility before adopting.

How TCA differs from MVVM

MVVM puts logic in an ObservableObject that a view observes, and the view model calls services directly. TCA puts logic in a pure reducer and pushes everything impure into Effect values that the store runs. The practical difference is what a test can do. With a view model you typically construct it with a mock service and assert on published properties. With TCA the README describes testing a feature, testing features composed of many parts, and writing end-to-end tests that show how side effects influence the app, which is possible because effects are values the test can control rather than calls the code makes behind your back. The trade is indirection: reading a TCA feature means following an action from the view into the reducer and back out to a new state, and developers used to MVVM will find that longer at first. MVVM also has no opinion about composition, so sharing state across screens is left to whatever pattern the team invents. TCA's answer is embedding child reducers, which is more machinery but is uniform across the codebase.

Maintenance, licence and upgrade cost

The repository is not archived and the last push was on 2026-09-18, so the project is being worked on. The licence is MIT, which permits commercial and closed-source use and requires that the copyright notice and permission notice travel with the source or substantial portions of it. That is a permissive arrangement, but it is not legal advice and your organisation's own review should confirm how it interacts with your distribution model. Upgrade cost is the part teams underestimate. TCA is a dependency with a macro-based API, so a major release can change how State and reducers are declared, and the presence of two Package manifests means the toolchain you build with determines which one applies. The release history shows several releases within a few months, so a pinned version will need revisiting. Budget for reading release notes and re-running your test suite on each bump rather than treating the dependency as fire-and-forget.

Editorial conclusion

Adopt TCA if you have more than one screen sharing state, a test suite you intend to keep honest, and at least one engineer willing to learn the reducer model before the first feature ships. Do not adopt it for a single-view app, a throwaway prototype, or a team that cannot absorb a new mental model on top of SwiftUI. Before committing, verify that the version you pin supports your minimum deployment targets, read the navigation and higher-order reducer case studies in Examples/CaseStudies, and confirm in Package.swift which Swift toolchain the release you plan to use requires.

Frequently asked questions

What does the Composable Architecture mean in the context of TCA?

It is a library for building applications where features are modelled as State, Action, Reducer and Store, so that state changes happen only in reducers and side effects are returned as Effect values. The README describes it as providing tools for state management, composition, side effects, testing and ergonomics.

Which architecture is best for SwiftUI?

The README does not rank architectures. It states that the Composable Architecture can be used in SwiftUI, UIKit and more, on any Apple platform, and that it is built with composition, testing and ergonomics in mind.

Is MVVM good for SwiftUI?

The README does not evaluate MVVM. It does describe an alternative in which logic lives in reducers and impure work is returned as effects the store runs, which the README presents as the basis for testing features, composed features and end-to-end side effect behaviour.

Does iOS use SwiftUI?

The README does not answer this. It only states that the Composable Architecture can be used in SwiftUI and UIKit on iOS, macOS, iPadOS, visionOS, tvOS and watchOS.

Official sources

  1. License: MIT
  2. pointfreeco/swift-composable-architecture on GitHub
  3. Project website
  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/pointfreeco-swift-composable-architecture.svg)](https://hysenlabs.com/projects/pointfreeco-swift-composable-architecture)