Learn

Redirects and Guards

Send users to another typed destination, deny a transition, protect unsaved work, and refresh policy when session state changes.

v1.1.0Beginner

Redirects and Guards

Use a Redirect when navigation should continue to a different Destination. Use a Guard when navigation should stop.

Redirect a signed-out user to Login

dart
final class AuthenticationRedirect implements NavigationRedirect {
  AuthenticationRedirect(this.session);
  final SessionState session;

  @override
  NavigationTarget<Object?>? redirect(NavigationPolicyContext context) {
    final destination = context.target.destination;
    if (session.isSignedIn || destination is LoginDestination) return null;

    return NavigationTarget<Object?>(
      destination: LoginDestination(returnTo: destination),
    );
  }
}

The original Account page is never rendered. Login receives the typed return target and can replace itself after sign-in.

Deny access without choosing another screen

dart
enum AccessDeniedReason { subscriptionRequired }

final class SubscriptionGuard implements NavigationGuard {
  SubscriptionGuard(this.account);
  final AccountState account;

  @override
  NavigationGuardDecision evaluate(NavigationPolicyContext context) {
    if (context.phase == NavigationGuardPhase.enter && !account.isPremium) {
      return const NavigationGuardDenied(
        reason: AccessDeniedReason.subscriptionRequired,
      );
    }
    return const NavigationGuardAllowed();
  }
}

The caller receives NavigationRejected; your UI can show an upgrade prompt without mutating the stack.

Protect unsaved changes

Check leave when moving away from an editor:

dart
if (context.phase == NavigationGuardPhase.leave && editor.hasChanges) {
  return const NavigationGuardDenied(reason: UnsavedReason.pendingChanges);
}

The Guard reports policy. A confirmation dialog is UI and should be handled by the caller or application layer, followed by a second explicit navigation request.

Re-evaluate when authentication changes

dart
final session = NavigationSession(
  id: const NavigationSessionId('main'),
  graph: createGraph(sessionState),
  policyRefresh: ListenableNavigationPolicyRefresh(sessionState),
);

When sessionState.notifyListeners() runs, the Session reconciles the current target. This is how sign-out can move an already-open private screen through the same policy pipeline.

Attach policies at the smallest useful boundary: Route for one page, Module for a feature, Mount for one placement, Graph for the whole application.