Building SwiftUI Navigation for a Modular App

Introduction In my previous post, I surveyed three approaches to SwiftUI navigation at scale: shared routers, navigation frameworks, and per-module coordinators. I explained the trade-offs of each. This post is the implementation. A demo project with five feature modules, a tab bar, a modal settings flow, an onboarding gate, deep linking, and unit tests. The architecture: Vertical feature modules that can’t see each other A generic Router per module that holds navigation state Each module composes its own views internally A single AppCoordinator for cross-module orchestration No coordinator per feature module The Module Structure App (composition root) ├── Home (tab — list → detail push) ├── Profile (tab — static screen, edit sheet) ├── Account (tab — logout action) ├── Onboarding (separate flow — experiment-based branching) ├── UserSettings (modal sheet) └── Navigation (shared — Router generic) Each feature package depends on Navigation but never on each other. The Navigation package contains only the generic Router. Pure infrastructure with no app-specific types. The App target is the only thing that imports everything. ...

March 18, 2026 · 11 min · Luke Jones

SwiftUI Navigation with Coordinators

SwiftUI Navigation with Coordinators: Scaling NavigationStack Without Losing Your Mind Introduction NavigationStack was released in iOS 16 and I was originally excited for it. For years before that, SwiftUI navigation felt like a collection of half measures: NavigationView, NavigationLink scattered through views, boolean bindings to trigger pushes, and a long list of weird hacks just to present screens conditionally. When things became truly complex, we inevitably fell back to UIHostingController, dragging UIKit back into places where SwiftUI was supposed to shine. ...

February 10, 2026 · 5 min · Luke Jones