25
Backend
04
Security
08
iOS
07
Infra

Build native macOS from the iOS SwiftUI target with an adaptive NavigationSplitView root

ADR-0070 ACCEPTED · 2026-06-15
Build native macOS from the iOS SwiftUI target with an adaptive NavigationSplitView root

Decision

Ship the Mac app from the same SwiftUI target as the iPhone app, compiled natively for macOS. Presentation may differ by platform; logic may not.

A control on the Mac and its counterpart on the iPhone call the same service method, and no Mac-only path through the domain exists. The trip root is adaptive: a NavigationSplitView with a sidebar and detail at regular width, and the existing tabs in a NavigationStack at compact width. A Mac window never reports a compact size class, so the Mac always gets the split layout that also serves the iPad.

Leaf views such as section content, forms and rows are shared unchanged, and only containers know about the platform. When a view needs a different shape on the Mac, we restructure the shared view and never copy it. Genuine platform differences, such as a sheet on one platform and inline content on the other, context menus, file import, menu commands and keyboard shortcuts, are small modifiers or #if os(...) branches at the exact point they differ. A Mac copy of a screen is not allowed.

Why

On a Mac the app ran as an iPhone-width column in a desktop window. We want the Mac to be first-class, but the usual routes fork the view tree, and every screen then exists twice with its behaviour maintained by hand in both. All behaviour already lives below the views (ADR-0003, ADR-0044), so changing a view's shape cannot change what its buttons do. A wrong layout is visible and gets fixed; forked logic is invisible and expensive. That asymmetry is why only presentation may differ.

Rejected alternatives

  • A separate macOS target. Two view trees kept in step by hand, which fail by quietly behaving differently.
  • Mac Catalyst. It keeps the iPhone idiom on the Mac and adds a translation layer with its own quirks. Native SwiftUI on macOS has less surface.
  • Mac-specific views in the same target. Cheaper than a separate target, with the same flaw: each screen exists twice, and the copies come to behave differently.
  • Leave the Mac as an iPhone column. Free, and it gives up on the Mac.
  • Another automation tool for macOS end-to-end flows. The flows from ADR-0069 have no macOS driver. Behaviour is shared and already covered by those flows, the Rust tests and unit tests that run on macOS. What differs on the Mac is layout, which does not justify another engine.

Consequences

A feature cannot ship iOS-only, by construction. Mac layout polish changes the iPhone's shared views, so both need checking. Nothing automated checks the Mac layout; we check it by running the Mac app and reviewing screenshots. The compact layout must stay as it is, because the approach depends on the iPhone experience being unchanged.