Skip to main content
NavigationUtils provides a unique approach to deeplinks by treating them as data. Define all your deeplinks in a single list using DeeplinkDestination, making them easy to manage, update, and customize. Defining deeplinks as data provides several advantages:
  • Centralization - Manage all deeplinks in one place instead of scattered throughout your code
  • Consistency - Every deeplink follows the same structure and pattern
  • Flexibility - Dynamically generate, modify, or filter deeplinks based on your app’s needs
  • Testability - Easy to test deeplink behavior without complex navigation setup
Create a list of DeeplinkDestination instances:
List<DeeplinkDestination> deeplinkDestinations = [
  DeeplinkDestination(
    deeplinkUrl: '/deeplink/login',
    destinationLabel: LoginPage.name),
  DeeplinkDestination(
    deeplinkUrl: '/deeplink/signup',
    destinationLabel: SignUpPage.name),
];

DeeplinkDestination properties

Each DeeplinkDestination can be configured with:

Required properties

  • deeplinkUrl - The URL pattern that triggers this deeplink (e.g., /deeplink/login)
  • destinationLabel or destinationUrl - Where to navigate when the deeplink is opened

Optional properties

DeeplinkDestination(
  deeplinkUrl: '/deeplink/login',
  destinationLabel: LoginPage.name,
  destinationUrl: '/login',
  backstack: [InitializationPage.name, StartPage.name],
  backstackRoutes: [InitializationRoute(), StartRoute()],
  excludeDeeplinkNavigationPages: [ForgotPassword.name],
  shouldNavigateDeeplinkFunction: () {
    if (AuthService.instance.isAuthenticated) return false;
    return true;
  },
  mapArgumentsFunction: (pathParameters, queryParameters) {
    // Remap or process path and query parameters.
    String referrerId = queryParameters['referrer'] ?? '';
    InstallReferrer.instance.setReferrerId(referrerId);

    return {'id': pathParameters['userId'] ?? ''};
  },
  runFunction: (pathParameters, queryParameters) async {
    // Arbitrary function call for handling deeplinks without doing navigation.
  },
  authenticationRequired: false,
)

Property descriptions

1

destinationLabel / destinationUrl

The named route or URL path where users navigate when opening this deeplink.
2

backstack / backstackRoutes

Define the route history stack. Only one of these can be set. Useful for ensuring users have proper navigation context after a deeplink.
3

excludeDeeplinkNavigationPages

List of pages where this deeplink should NOT navigate from (e.g., during onboarding).
4

shouldNavigateDeeplinkFunction

Custom function to determine if navigation should occur. Return false to prevent navigation.
5

mapArgumentsFunction

Transform or process path and query parameters before navigation.
6

runFunction

Execute custom logic without navigation, or after navigation completes. Perfect for analytics, sharing, or showing dialogs.
7

authenticationRequired

Boolean indicating whether the user must be authenticated to access this deeplink.
Use NavigationUtils.openDeeplinkDestination to process URIs and navigate:
class DefaultRouteParser {
  static bool openDeeplink(Uri? uri) {
    return NavigationUtils.openDeeplinkDestination(
      deeplinkDestinations: deeplinkDestinations,
      routerDelegate: NavigationManager.instance.routerDelegate,
      uri: uri,
      authenticated: AuthService.instance.isAuthenticated,
      currentRoute: NavigationManager.instance.currentRoute,
      excludeDeeplinkNavigationPages: doNotNavigateDeeplinkPages,
    );
  }
}

Parameters

  • uri - The URI object representing the deeplink
  • deeplinkDestinations - Your list of deeplink definitions
  • routerDelegate - The router delegate that handles navigation
  • authenticated - Whether the user is authenticated (default: true)
  • currentRoute - The current route, used to check exclusion lists
  • excludeDeeplinkNavigationPages - Global list of pages to exclude from deeplink navigation
  • redirectFunction - Optional function to redirect to another route
Define deeplinks with dynamic path segments:
DeeplinkDestination(
  deeplinkUrl: '/link/project/:projectId',
  destinationUrl: '/project/:projectId',
)
When users open /link/project/123, they navigate to /project/123 with projectId available in routeData.pathParameters. Query parameters are automatically extracted and passed:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/product',
  destinationUrl: '/product',
  mapArgumentsFunction: (pathParameters, queryParameters) {
    // Access query parameters
    String referrerId = queryParameters['referrer'] ?? '';
    InstallReferrer.instance.setReferrerId(referrerId);
    
    return {'id': queryParameters['id'] ?? ''};
  },
)
Opening /deeplink/product?id=123&referrer=email processes both query parameters. Use deeplinks to trigger functionality without navigation:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/share/:postId',
  runFunction: (pathParameters, queryParameters) async {
    String postId = pathParameters['postId'] ?? '';
    await ShareService.sharePost(postId);
    // Show share sheet without navigating
  },
)
The runFunction is also called after navigation completes, allowing you to run logic after the user reaches the destination page.
Redirect deeplinks based on custom logic:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/content/:id',
  destinationUrl: '/content/:id',
  redirectFunction: (pathParameters, queryParameters, redirect) {
    if (pathParameters.containsKey('id') && queryParameters.containsKey('action')) {
      redirect(
        label: 'newDestination',
        pathParameters: {'id': pathParameters['id']!},
        queryParameters: {'action': queryParameters['action']!},
        globalData: {'additionalData': 'example'}
      );
      return Future.value(true);
    }
    return Future.value(false);
  },
)
The redirectFunction returns:
  • true - Navigation proceeds to the redirected destination
  • false - Navigation proceeds to the original destination
Protect deeplinks that require authentication:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/profile',
  destinationUrl: '/profile',
  authenticationRequired: true,
)
Pass the authentication state when opening:
NavigationUtils.openDeeplinkDestination(
  uri: uri,
  deeplinkDestinations: deeplinkDestinations,
  routerDelegate: NavigationManager.instance.routerDelegate,
  authenticated: AuthService.instance.isAuthenticated, // Check auth state
);
If authenticationRequired is true and authenticated is false, the deeplink navigation will be blocked.

Conditional navigation

Prevent navigation based on custom logic:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/premium',
  destinationUrl: '/premium',
  shouldNavigateDeeplinkFunction: () {
    // Only navigate if user has premium
    if (UserService.instance.isPremium) return true;
    return false;
  },
)

Async navigation

Perform async operations before navigating:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/secure',
  destinationUrl: '/secure',
  shouldNavigateDeeplinkFunction: () async {
    // Check async authentication
    bool isVerified = await BiometricService.verify();
    return isVerified;
  },
)
Prevent deeplinks from navigating while on certain pages:
// Global exclusion list
List<String> doNotNavigatePages = [
  OnboardingPage.name,
  TutorialPage.name,
];

NavigationUtils.openDeeplinkDestination(
  uri: uri,
  deeplinkDestinations: deeplinkDestinations,
  routerDelegate: NavigationManager.instance.routerDelegate,
  currentRoute: NavigationManager.instance.currentRoute,
  excludeDeeplinkNavigationPages: doNotNavigatePages,
);
You can also exclude pages per deeplink:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/settings',
  destinationUrl: '/settings',
  excludeDeeplinkNavigationPages: [SetupWizard.name],
)

Best practices

Organize deeplinks by feature
List<DeeplinkDestination> get authDeeplinks => [
  DeeplinkDestination(...),
];

List<DeeplinkDestination> get contentDeeplinks => [
  DeeplinkDestination(...),
];

List<DeeplinkDestination> get allDeeplinks => [
  ...authDeeplinks,
  ...contentDeeplinks,
];
Use consistent URL patternsPrefix all deeplinks with /deeplink/ or /dl/ to distinguish them from regular routes:
DeeplinkDestination(
  deeplinkUrl: '/deeplink/product/:id',
  destinationUrl: '/product/:id',
)

Next steps

Route guards

Protect routes with authentication and custom guards

Path parameters

Use dynamic segments in deeplinks

Build docs developers (and LLMs) love