Deep Linking with React Navigation v6: From URL to Screen in Minutes
Learn how to turn external URLs into in‑app navigation with React Navigation v6. A step‑by‑step guide, code snippets, platform quirks, and trade‑offs to help you add deep linking to your React Native app.
15 Jan 2026, 15:12 UTC

Problem: How to open a specific screen from an external URL?
When users click a link in an email, a web page, or another app, you want the React Native app to open to a particular screen—maybe a product detail or a user profile. Without a proper deep‑linking setup, the app launches to its root and the user has to navigate manually. This blog shows how to wire up React Navigation v6 so that a URL like https://myapp.com/details/42 or myapp://details/42 takes the user straight to the Details screen with the correct id parameter.
The Core Idea: LinkingConfiguration Maps URLs to Routes
React Navigation v6 exposes a linking prop on NavigationContainer. You pass a LinkingConfiguration object that contains two parts:
- prefixes – the schemes or hostnames that the app will recognize.
- config – a tree that maps route names to URL patterns.
When the OS delivers a URL to the app, React Navigation parses it against this tree and automatically navigates to the matching screen, injecting any captured parameters.
Setting Up LinkingConfiguration
Define the configuration once, ideally in its own file so you can import it wherever you need it.
// linking.js
export const linkingConfig = {
prefixes: ['https://myapp.com', 'myapp://'], // host and custom scheme
config: {
screens: {
Home: 'home',
Details: 'details/:id', // :id will be parsed into route params
// add more screens here
},
},
};
Then pass it to the navigation container:
import { NavigationContainer } from '@react-navigation/native';
import { linkingConfig } from './linking';
function App() {
return (
<NavigationContainer linking={linkingConfig}>
{/* your navigators */}
</NavigationContainer>
);
}
Platform‑Specific Setup
React Navigation handles the parsing, but the OS must know that your app can receive the URL. Add the following entries:
iOS – Info.plist
Insert a CFBundleURLTypes array with a dictionary that includes CFBundleURLSchemes and CFBundleURLName:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
<key>CFBundleURLName</key>
<string>com.example.myapp</string>
</dict>
</array>
For universal links (https://myapp.com), add a Associated Domains capability and host the apple-app-site-association file on your web server.
Android – AndroidManifest.xml
Define an intent-filter inside the <activity> that declares the custom scheme and host:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="" />
<data android:scheme="https" android:host="myapp.com" />
</intent-filter>
</activity>
Missing these entries will cause the OS to ignore the URL.
Concrete Worked Example
Assume the following screen hierarchy:
Home– root screen.Details– shows an item based onid.
When a user opens https://myapp.com/details/42 from Safari on iOS or via adb shell am start -a android.intent.action.VIEW -d 'myapp://details/42' on Android, the app should appear on the Details screen with route.params.id === 42.
To verify the navigation works both when the app is fresh and when it is already running, use the Linking API:
import { useEffect } from 'react';
import { Linking } from 'react-native';
function App() {
useEffect(() => {
// Handle the URL that launched the app
const getInitial = async () => {
const url = await Linking.getInitialURL();
if (url) console.log('App launched from URL:', url);
};
getInitial();
// Listen for URL changes while the app is running
const listener = Linking.addEventListener('url', ({ url }) => {
console.log('URL received while running:', url);
});
return () => listener.remove();
}, []);
return (/* NavigationContainer as shown earlier */);
}
Run the app, then trigger the URL from an external source. Observe the console logs and the navigation stack. If the Details screen receives id=42, the configuration is correct.
Trade‑offs & Limitations
- Route Synchronization – The
configtree must stay in sync with your navigator definitions. Adding a new screen without updating the map will cause the link to fail. - Platform Boilerplate – iOS and Android require different XML/plist edits. Forgetting one step will silently break linking.
- Security – Any URL that resolves to a protected screen bypasses the usual login flow. Always guard sensitive routes by checking authentication before navigation.
- Background Behavior – If the app is in the background, the OS may defer the deep link until the user brings the app to the foreground. Use
Linking.getInitialURLand event listeners to handle this gracefully.
Actionable Closing
- Create a
linking.jsfile with your prefixes and config. - Update
Info.plist(iOS) andAndroidManifest.xml(Android) with the necessary URL types or intent filters. - Wrap your navigator in
NavigationContainer linking={linkingConfig}. - Test the deep link from both a fresh launch and an already‑running instance.
- Guard sensitive screens and keep the config tree updated whenever routes change.
With these steps, your React Native app can now respond to external URLs, improving discoverability and integration with web, email, and other apps. Happy linking!
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.