Navigating Navigator 2.0 with Flow Builder

November 20, 2020
November 20, 2020
updated on
October 7, 2022
Guest Contributor

The arrival of Navigator 2.0 in Flutter 1.22 was a long-anticipated addition to the Flutter ecosystem. With this update, we can now access the pages API, which gives us more freedom for navigating through different flows in an application. 

We built Flow Builder to make navigating with Navigator 2.0 even simpler by taking out all of the manual steps you would have to do when using just the pages API. Flow Builder also maintains a declarative API, allowing you to decouple the routing logic from the UI. This gives you the freedom to implement complex routing for deep links and custom navigation flows.

Since Flow Builder represents navigation as a function of state, it can be used with whatever state management solution you have chosen. Most importantly, it is fully testable.

The package also handles things that you would normally have to manually account for with the pages API, such as pressing the hardware back button on Android and swiping from left on iOS. Additionally, it allows developers to define complex nested flows driven by independent state.

How to Use Flow Builder

There are three different use cases built into the package, including an example onboarding flow, profile creation, and location selection. We’ll walk through the use case for profile creation here:

First, define a flow state that will drive the navigation.

class Profile {
  const Profile({, this.age, this.weight});

  final String? name;
  final int? age;
  final int? weight;

  Profile copyWith({String? name, int? age, int? weight}) {
    return Profile(
      name: name ??,
      age: age ?? this.age,
      weight: weight ?? this.weight,

Then, create a FlowBuilder.

Widget build(BuildContext context) {
  return const FlowBuilder(
    state: Profile(),
    onGeneratePages: onGenerageProfilePages,

Define your onGeneratePages function, which will be responsible for determining the navigation stack based on the flow state.

List onGenerateProfilePages(Profile profile, List pages) {
  return [
    MaterialPage(child: ProfileNameForm()),
    if ( != null) MaterialPage(child: ProfileAgeForm()),
    if (profile.age != null) MaterialPage(child: ProfileWeightForm()),

Now you can plug in an existing state management solution to maintain and manipulate the flow state OR you can use the built-in FlowController to manipulate the flow state.

  child: const Text('Continue'),
  onPressed: () {
      .update((profile) => profile.copyWith(name: 'Felix'));

To complete a flow, use the complete API on FlowController and optionally modify the flow state as needed.

  child: const Text('Complete'),
  onPressed: () {
    context.flow().complete((profile) => profile);

With that, you’ve completed your first flow! 

For more examples, check out the repo here.

We want to hear from you!

Flow Builder is currently under development, but we've tested it in a few projects internally at VGV to verify the abstraction. Before we release a stable version, we would love to hear from you about how to make this better and any additional examples you’d like to see added to the repo! Please open an issue here with feedback and suggestions. 


No items found.

More Stories