Comparison · 2026 · 07 · 16 · Architecture

napkin vs The Composable Architecture: tree of actors vs reducer graph

The Composable Architecture (TCA) and napkin aren't two answers to the same question. TCA is a state-management architecture: value-type State, Actions, Reducers, a Store. napkin is a screen-tree architecture: actor Interactors, @MainActor Routers and Presenters, composed per feature. This page compares them — including where TCA is simply the better choice.

What's actually different: two shapes of app

TCA, by its own README, is a library for building applications "with composition, testing, and ergonomics in mind" — you model each feature as a State type, an Action enum, and a @Reducer that evolves state and returns effects, all driven by a Store. It's actively maintained by Point-Free: version 1.26.0 shipped June 9, 2026 (with Xcode 27 Beta 1 fixes), the seventh release of 2026, and the repo sits at roughly 14.8k stars under an MIT license.

napkin models an app as a tree of screen and flow units — the Router-Interactor-Builder pattern from Uber's RIBs, rebuilt on Swift 6 concurrency. Business logic runs in final actor interactors off the main thread; routing and presentation are @MainActor; parents hear from children through listener protocols. State isn't one composed value graph — it lives in each unit and streams down the tree.

Neither shape is "right." Reducer composition gives TCA a single, inspectable source of truth per feature. The unit tree gives napkin hard isolation boundaries and per-screen ownership. Which one fits depends on whether your app's complexity lives in its state transitions or in its flows between screens.

Observation: not a differentiator — but different mechanics

Both frameworks use Swift's observation model, so don't choose on that axis. TCA has shipped Observation-based state since v1.7 (January 2024 — "100% backwards compatible," per Point-Free's announcement), with its own @ObservableState macro because native @Observable is class-only and TCA state is value types; Point-Free even back-ported observation to iOS 13 via their Perception library. napkin uses the native @Observable macro directly on its class-based presenters — no macro layer of its own, no back-port, because its floor is new OSes anyway.

Testing

Testing is TCA's crown jewel. Its TestStore is exhaustive by default: per the maintainers' FAQ, "you must also assert on how effects feed their data back into the system" — every state change and every received action is accounted for, with a non-exhaustive opt-out (exhaustivity = .off) when you want it. If you want your tests to fail the moment any state transition changes, nothing else in the Swift ecosystem does this as thoroughly.

napkin's testing story is deliberately plainer: interactors are actors, so you unit-test them with ordinary XCTest — inject a mock presenter, router, and listener, drive the lifecycle, assert on recorded calls. No test runtime, no assertion DSL; also no exhaustiveness guarantee. You get Swift's own tools, not a framework's.

What adopting each one costs

TCA's maintainers are unusually honest about fit, and their FAQ is worth quoting: "We do not recommend people use TCA when they are first learning Swift or SwiftUI," and "We also don't think TCA really shines when building simple 'reader' apps that mostly load JSON from the network and display it." They acknowledge that "often people complain of boilerplate in TCA," attributing much of it to the legacy view-store era, and argue a modern TCA feature needs few more lines than vanilla SwiftUI — a maintainer claim you should test on your own code.

Two adoption facts to weigh. First, platform floors cut against napkin here: TCA supports iOS 16+ (Swift 6.1+, after its 1.24.0 deprecation wave); napkin requires iOS 26/macOS 26. Second, churn: TCA is openly preparing a 2.0 — 1.24.0 was a deprecations-only release (ViewStore, TaskResult, and @BindingState are now hard-deprecated), and 1.25.0 shipped "a significant batch of deprecations that pave the way for Composable Architecture 2.0" — so 1.x adopters should budget for a migration. napkin's risk is the opposite kind: not migrating off a large 1.x surface, but betting on a young API with a tiny community behind it.

On learning resources: TCA's canonical deep-dive is Point-Free's subscription episode collection (16 sections, 58½ hours), alongside free DocC docs and an interactive tutorial. Their maintenance pace is real — 1.26.0 shipped Xcode 27 Beta 1 fixes — and, in their own words, "this kind of support and turnaround for our open source projects is only thanks to the support of our subscribers." napkin has free DocC docs, a runnable example app, and no commercial arm.

Comparison table

Facts as of July 16, 2026 — versions and stars are point-in-time.
TCAnapkin
ShapeState/Action/Reducer/StoreTree of screen units (Router-Interactor-Builder)
Latest release1.26.0 (June 9, 2026); 2.0 in preparation2.1.5
State observation@ObservableState macro (value types; iOS 13 back-port via Perception)Native @Observable on class presenters
ConcurrencyEffects system; Swift Concurrency integrationfinal actor interactors, @MainActor routers and presenters
TestingTestStore, exhaustive by defaultPlain XCTest + mocks
Min platformiOS 16, Swift tools 6.1iOS 26 / macOS 26, Swift tools 6.2
DependenciesPoint-Free libraries (e.g. Perception for pre-iOS-17 observation)swift-docc-plugin only (docs)
LicenseMITApache-2.0
GitHub stars~14.8k2
Learning resourcesFree DocC + tutorial; 58.5-hour subscription collectionFree DocC + example app

When to choose TCA

  • Your app's complexity is in state: many sources of truth to compose, undo, persist, or share across features.
  • Exhaustive, deterministic tests of every state transition are a requirement, not a nice-to-have.
  • You need iOS 16 — napkin's iOS 26 floor is a hard stop.
  • You value a large ecosystem, deep documentation, and a funded team that keeps pace with beta SDKs.

When to choose napkin

  • Your app's complexity is in flows: login trees, tab hierarchies, multi-step features owned by teams.
  • You want business logic structurally off the main actor — actors as the unit of design, not a convention.
  • You prefer the platform's own vocabulary — @Observable, AsyncStream, XCTest — over a framework's DSL.
  • You're on iOS 26/macOS 26 and comfortable betting on a young, small project.

And a genuinely fine third answer, borrowed from TCA's own FAQ: start with vanilla SwiftUI and adopt an architecture when the pain shows up. Both frameworks will still be here.

Related: napkin vs RIBs · napkin vs VIPER · When to use napkin · FAQ