I Built a SwiftUI Navigation Library Because NavigationLink Doesn’t Scale
SwiftUI is powerful, but if you’ve built anything beyond a demo app, you’ve probably struggled with navigation.
I Built a SwiftUI Navigation Library Because NavigationLink Doesn’t Scale
SwiftUI is powerful, but if you’ve built anything beyond a demo app, you’ve probably struggled with navigation.
After dealing with real-world SwiftUI projects, I decided to build a small open-source library called MKNavigatation — a ViewModel-driven, SwiftUI-native navigation solution inspired by the Coordinator pattern.
This article explains:
- Why SwiftUI navigation becomes painful
- What problem MKNavigatation solves
- The architecture behind it
- How you can use it in your own apps
The Problem with SwiftUI Navigation
SwiftUI gives us tools like:
NavigationLinkNavigationStackNavigationPath
They work fine… until your app grows.
Common issues I faced:
- Navigation logic leaking into Views
- Conditional
NavigationLinks everywhere - Hard-to-test navigation flows
- Difficult “pop to root” or “reset stack” logic
- Poor separation of concerns in MVVM
In short:
Navigation becomes tightly coupled with UI.
This goes against clean architecture and makes scaling painful.
Why Not Use the Classic Coordinator Pattern?
The Coordinator pattern is great in UIKit, but in SwiftUI:
- It often relies on UIKit bridges
- It fights SwiftUI’s state-driven nature
- It adds unnecessary complexity
I wanted:
- A SwiftUI-native solution
- No UIKit
- No
NavigationLinkin Views - Navigation controlled from ViewModels
That’s how MKNavigatation was born.
Core Idea Behind MKNavigatation
The idea is simple:
***- Views should never decide navigation.
- ViewModels should express intent.
- A Router should own navigation state.***
So the flow becomes:
User Action
↓
View
↓
ViewModel
↓
NavigationRouter
↓
NavigationStack
This keeps responsibilities clean and predictable.
Architecture Overview
MKNavigatation is built around three core concepts:
1. Route
A route is an enum that represents screens.
enum AppRoute: NavigationRoute {
case home
case profile(userId: String)
case settings
}
Routes are:
- Type-safe
- Easy to reason about
- Centralized
2. NavigationRouter (Coordinator-like)
The router:
- Owns
NavigationPath - Exposes simple navigation APIs
- Is observable by SwiftUI
final class NavigationRouter<Route: NavigationRoute>: ObservableObject {
@Published var path = NavigationPath()
func push(_ route: Route) {
path.append(route)
}
func pop() {
path.removeLast()
}
func popToRoot() {
path.removeLast(path.count)
}
}
This is the heart of navigation.
3. NavigationContainer
A simple wrapper around NavigationStack:
NavigationStack(path: $router.path) {
content
}
This connects SwiftUI to the router without polluting views.
ViewModel-Driven Navigation (The Key Benefit)
Navigation is triggered only from ViewModels:
final class HomeViewModel {
private let router: NavigationRouter<AppRoute>
init(router: NavigationRouter<AppRoute>) {
self.router = router
}
func openProfile() {
router.push(.profile(userId: "101"))
}
}
And the View stays clean:
struct HomeView: View {
let viewModel: HomeViewModel
var body: some View {
Button("Go to Profile") {
viewModel.openProfile()
}
}
}
No NavigationLink.
No routing logic in the UI.
Just intent.
Why This Scales Well
This approach works especially well for:
- Medium to large SwiftUI apps
- Modular architectures (SPM + feature modules)
- MVVM or Clean Architecture
- Teams that care about testability
- Interview-ready system design
It also makes:
- Deep linking
- Stack replacement
- Analytics tracking much easier to add later.
When You Should (and Shouldn’t) Use This
✅ Use MKNavigatation if:
- Your app has multiple flows
- You want clean MVVM separation
- Navigation logic is growing
- You care about testability
❌ Don’t use it if:
- Your app has one or two screens
- You’re building a throwaway demo
Open Source & Future Plans
MKNavigatation is open-source and intentionally minimal.
Planned improvements:
- Modal & sheet navigation
- Deep linking support
- Multi-router per feature
- Navigation analytics hooks
You can check out the repository here: 👉 **https://github.com/MayannkKankrecha/MKNavigatation**
Final Thoughts
SwiftUI navigation doesn’t need to be messy.
By:
- Moving navigation out of Views
- Letting ViewModels express intent
- Centralizing state in a Router
…you get a system that’s clean, scalable, and easy to reason about.
If you’ve struggled with SwiftUI navigation, I hope **MKNavigatation** helps you the same way it helped me.
Thanks for reading 👋 Happy coding 🚀
메타데이터
- post_id
- ffc28dc76e38
- slug
- i-built-a-swiftui-navigation-library-because-navigationlink-doesnt-scale-ffc28dc76e38
- url
- https://medium.com/@kankrechamayank/i-built-a-swiftui-navigation-library-because-navigationlink-doesnt-scale-ffc28dc76e38
- canonical_url
- https://medium.com/@kankrechamayank/i-built-a-swiftui-navigation-library-because-navigationlink-doesnt-scale-ffc28dc76e38
- author_url
- https://medium.com/@kankrechamayank
- status
- ok
- fetched_at
- 2026-06-27 23:56:40