Handling Deep Links in React Navigation without Breaking the Back Stack
Learn how to implement deep linking in React Navigation while maintaining a logical back stack and handling dynamic parameters for nested navigators.
25 Mar 2026, 04:19 UTC

The Deep Link Navigation Trap
The primary challenge with deep linking isn't getting a URL to open a screen; it's ensuring the user isn't trapped on that screen. When a user clicks a link to a specific product or profile, they expect the system back button to take them to the app's home page or a parent category, not exit the application entirely.
To solve this, React Navigation uses a linking configuration that maps URL paths to your navigator hierarchy. When a link is triggered, the library doesn't just push a screen; it reconstructs the navigation state based on your configuration, effectively "filling in" the stack behind the target screen.
Mapping URLs to Nested Navigators
In a production app, screens are rarely flat. You likely have a Stack navigator nested inside a Tab navigator. Your linking configuration must mirror this nesting to ensure the state is restored correctly.
The config object acts as a map. If a path is nested inside an object, React Navigation understands that it needs to activate the parent navigator first. For example, a path mapped under a SettingsStack key will ensure the Settings tab is active when the user arrives at a specific settings page.
Implementation: Dynamic Routing Example
Assume a version of React Navigation 6.x or 7.x. The following configuration handles a custom URI scheme (my-app://) and dynamic user profiles.
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['my-app://', 'https://myapp.com'],
config: {
screens: {
Home: 'home',
UserTabs: {
screens: {
Profile: 'user/:id', // Dynamic parameter
Settings: 'settings',
},
},
},
},
};
export default function App() {
return (
<NavigationContainer linking={linking}>
{/* Your Navigator Components Here */}
</NavigationContainer>
);
}
How to verify the routing
To test this without building a full website for Universal Links, use the CLI to trigger the URI scheme on a running emulator or simulator.
- Android: Run
npx uri-scheme open "my-app://user/123" --android - iOS: Run
xcrun simctl openurl booted "my-app://user/123"
Expected Result: The app should open the Profile screen, and route.params.id should equal "123". Pressing the hardware back button should return the user to the Home screen.
Native Configuration Requirements
The JavaScript configuration only handles the routing once the app is open. You must still configure the native OS to recognize the URL:
- iOS: Add the URL scheme to
Info.plistunderCFBundleURLTypes. For Universal Links, enableAssociated Domainsin the Entitlements file. - Android: Add an
<intent-filter>to theAndroidManifest.xmlwithin the main activity, specifying theandroid:schemeandandroid:host.
Trade-offs and Maintenance
As your app grows, the config object can become a maintenance burden. Deeply nested structures lead to verbose mapping files that are easy to break during refactors.
Limitation: React Navigation's default linking behavior is static. If you need to validate a token or check user permissions before deciding which screen to show based on a link, the config object is insufficient. In those cases, you must use a custom getStateFromPath function to intercept the URL and return a custom navigation state object.
Final Verification Checklist
Before deploying deep links, verify these three states:
- Cold Start: Does the link open the correct screen when the app is completely closed?
- Warm Start: Does the link work when the app is already running in the background?
- Stack Integrity: Does the back button lead to the expected parent screen, or does it kill the app process?
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.