Introduction
Deep linking lets mobile apps respond to incoming URLs and route users directly to specific screens. In Flutter, handling URL routes smartly enhances user experience by reducing navigation friction. This tutorial explores core techniques—URL strategies, Navigator 2.0 integration, link listeners, and testing—to implement deep links effectively.
Understanding Deep Linking in Flutter
Flutter’s navigation system can map URL paths to widget routes. On the web, the browser URL bar drives navigation, but on mobile, you need to parse incoming URIs. A deep link typically follows a custom scheme (myapp://) or an HTTPS fallback (https://example.com/page). When the OS receives a link, it launches your Flutter app and forwards the URI. Inside your app, you inspect the URI and translate its path and query parameters into routing instructions.
Setting Up URL Strategies
For web and mobile consistency, configure URL strategies in your pubspec.yaml and main.dart.
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void main() {
setUrlStrategy(PathUrlStrategy());
runApp(MyApp());
}On mobile, register custom schemes in AndroidManifest.xml and Info.plist. For Android:
<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="example.com"/>
</intent-filter>
iOS requires CFBundleURLTypes entries with URL schemes matching your app ID.
Integrating with Navigator 2.0
Navigator 2.0 exposes a declarative approach to routing using Router, RouteInformationParser, and RouterDelegate. Create a custom RouteInformationParser to convert RouteInformation (location) into a typed configuration:
class MyRouteInfoParser extends RouteInformationParser<RouteConfig> {
@override
Future<RouteConfig> parseRouteInformation(
RouteInformation info) async {
final uri = Uri.parse(info.location!);
if (uri.pathSegments.contains('product')) {
return ProductConfig(id: uri.queryParameters['id']);
}
return HomeConfig();
}
}The RouterDelegate responds to that configuration by updating the Navigator.pages stack.
Handling Incoming Links
Use the uni_links package to listen for incoming URIs at runtime. Inside a stateful widget’s initState, register a link stream:
StreamSubscription _sub;
@override
void initState() {
super.initState();
_sub = uriLinkStream.listen((Uri? uri) {
if (uri != null) handleDeepLink(uri);
});
}
void handleDeepLink(Uri uri) {
if (uri.path == '/profile') {
Navigator.pushNamed(context, '/profile',
arguments: uri.queryParameters);
}
}Remember to cancel the subscription in dispose().
Testing Deep Links
Testing deep links ensures reliability across platforms. On Android, use adb:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://example.com/product?id=42" com.example.myapp
On iOS Simulator, use xcrun:
xcrun simctl openurl booted "myapp://example.com/profile?user=alice"
For Flutter Web, navigate directly to https://localhost:5000/product?id=42. Verify that your RouteInformationParser and RouterDelegate update the displayed page accordingly.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
Deep linking in Flutter involves configuring URL strategies, integrating Navigator 2.0, listening for incoming URIs, and rigorous testing. By mapping URL segments to typed route configurations, you streamline navigation and deliver targeted content. Implement these patterns to provide seamless entry points into your app, whether users click web links, QR codes, or in-app banners.