SwiftUI.cc
Fix
Fix

SwiftUI NavigationView Deprecated: How to Migrate to NavigationStack

NavigationView was deprecated in iOS 16. Learn how to migrate to NavigationStack for modern navigation in SwiftUI.

5 min readUpdated 2026-06

The Problem

In iOS 16, Apple deprecated NavigationView and introduced NavigationStack as the new preferred way to handle navigation in SwiftUI. If you're still using NavigationView, you may see a warning like:

'NavigationView' is deprecated in iOS 16.0: Use NavigationStack instead.

Here's an example of the old pattern using NavigationView:

// ❌ Wrong (Deprecated)
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink("Go to Detail", destination: Text("Detail View"))
        }
    }
}

Root Cause

In iOS 16, Apple introduced NavigationStack to replace NavigationView. The change was made to provide more powerful and flexible navigation behaviors, especially for deep linking and programmatic navigation. Unlike NavigationView, which relied on a parent-child relationship to manage the navigation hierarchy, NavigationStack uses a data-driven approach with a path binding that allows direct manipulation of the navigation stack.

This shift gives developers more control over the navigation lifecycle and enables features like conditional navigation and dynamic path updates.

The Fix

To update your code, replace NavigationView with NavigationStack and use a path binding to control navigation state:

// ✅ Fixed
import SwiftUI

struct ContentView: View {
    @State private var path = [Int]()

    var body: some View {
        NavigationStack(path: $path) {
            NavigationLink("Go to Detail", value: 1)
                .navigationDestination(for: Int.self) { _ in
                    Text("Detail View")
                }
        }
    }
}

This new approach uses a generic path array to push views onto the stack. Each NavigationLink uses a value that matches the type in the path, and navigationDestination(for:) defines how to display the view for that value.

Alternative Approaches

1. Using NavigationPath for Shared Navigation State

If you need to manage navigation across multiple views or view models, you can use NavigationPath as a shared state object:

class Router: ObservableObject {
    @Published var path = NavigationPath()
}

struct ContentView: View {
    @StateObject private var router = Router()

    var body: some View {
        NavigationStack(path: $router.path) {
            Button("Go to Detail") {
                router.path.append(1)
            }
            .navigationDestination(for: Int.self) { _ in
                Text("Detail View")
            }
        }
    }
}

2. Conditional Navigation

You can also use the path to conditionally show views or reset navigation:

Button("Reset") {
    path = []
}

Affected iOS Versions

  • NavigationView was deprecated in iOS 16.
  • NavigationStack was introduced in iOS 16.
  • For apps targeting iOS 15 or earlier, continue using NavigationView.