Skip to main content

Choosing modules

An app is made of the modules you ask for and the modules they need. You name modules with -m or pick them in the questions of smf create, and SMF adds the rest.

Roles and the modules that provide them​

Most modules provide a role, a part of the app that other modules count on without knowing which module provides it. An app has at most one provider of most roles, while crash reporting and analytics can have several.

Role-mWhat the module doesIn an app
App entryflutter_coreThe Flutter project: main(), start-up, root widget, native projectsalways, added by SMF
Routergo_routerRoutes of the features, typed navigationnone or one
Layoutbottom_tabsTabs at the bottom for the features' destinations, in the colors of the themenone or one
Settings screensettingsA screen with the settings of the modules in one group, a row for eachnone or one
State managementblocBLoC with flutter_blocnone or one
riverpodRiverpod with flutter_riverpod
Themematerial_themeA light and a dark Material 3 theme with a palette and a bundled font, and the theme mode that the user selectsnone or one
Localizationgen_l10nThe texts of the app in ARB files, in the language of the device or in the one that the user chosenone or one
Dependency injectionget_itService locator with get_itnone or one
Eventsevent_busA service that delivers events between parts of the appnone or one
Preferencesshared_preferencesThe settings of the app (not secrets), remembered between its launchesnone or one
Crash reportingfirebase_crashlyticsReports errors to Firebase Crashlyticsany number
Analyticsfirebase_analyticsRecords events and screen views in Firebase Analyticsany number
Authenticationfirebase_authSigns users in with Firebase Authentication, with an email address and a password or as anonymous usersnone or one

Four modules provide no role:

Kind-mWhat the module does
FeaturehomeA start screen at /home, which welcomes the developer of the app and lists the next steps
FeatureonboardingThe onboarding that a new user goes through on the first launch of the app
Featuresign_inThe screens of sign-in, sign-up and password reset for an email address and a password, and the screen of the account
Infrastructurefirebase_coreSets up Firebase, for the other Firebase modules

Each module has a page of its own.

What SMF adds for you​

  • flutter_core goes into every app.
  • A module brings the modules it depends on: firebase_crashlytics, firebase_analytics and firebase_auth bring firebase_core.
  • A module that requires a role brings its provider when only one module provides it. Features need a router, and so does the layout, so home, settings or bottom_tabs brings go_router. A module that needs dependency injection brings get_it. material_theme, gen_l10n and onboarding each remember something between the launches of the app, so each brings shared_preferences. sign_in brings firebase_auth, which keeps the accounts, and settings, where the entry of the account is.

When several modules provide a required role, a run in a terminal asks which one to use. A run without a terminal stops and asks you to add one of them to -m. Before it generates the app, SMF prints each module it added and why.

How the modules combine​

Screens need a router​

A feature declares its routes for whatever router the app has. An app without a router shows the fallback start screen, which names the app and tells you where its first screen goes, and so does an app with a router but no screen to start on.

The layout shows the destinations of the features​

A feature can mark a route as a destination of the main navigation, as home does. With bottom_tabs, every destination becomes a tab, in the order the features were chosen. With one destination the tab bar is hidden, and without any the app has no main navigation. The bar holds at most five tabs. A feature whose destination does not fit is left out with a warning, and with --strict the run stops instead.

Without a layout, the app has no main navigation to lead to its destinations. smf create then warns of each destination other than the one that the app starts on, by its path and its module:

[WARN] No module provides the layout role, so the app has no main navigation to lead to the destination /settings (settings). Choose a provider of the role, or open it from a screen of yours with context.nav.

The app is generated all the same, also with --strict.

The settings screen is a feature too​

settings provides the settings screen role, and it is a feature with a route of its own, so it needs a router and its screen is a destination. With bottom_tabs, Settings becomes a tab next to the tabs of the other features. Without a layout, nothing that SMF generates opens the screen, and your own code opens it; see settings.

A module or a role with a setting gives the settings screen role a row, and the screen shows all of them, whichever module provides the screen. The theme mode of material_theme and the language of gen_l10n each have one, and sign_in has the row of the account. In an app without a settings screen, the mode and the language work without their rows. In an app with settings and no setting, the screen shows a note for you where the rows go.

Preferences remember what the user chose​

A module that keeps something the user chose saves it through the preferences role, which shared_preferences provides. The theme mode of material_theme and the language of gen_l10n are kept this way, and with settings the screen has a row for each. The preferences are for settings and not for secrets: nothing in them is encrypted, so a token, a password or a key never goes there. See Preferences and settings.

Texts follow the language of the app​

A module gives its texts to the localization role, in English and in the other languages that it has them in. With gen_l10n, the app keeps them in ARB files and shows them in the language of the device, and you add your own texts and languages there. Every app has texts in English and in Ukrainian, those of the fallback start screen of flutter_core, so an app with gen_l10n is in both languages unless --locales says otherwise. Without a module that provides the localization, the modules show their texts in English. See Languages.

The onboarding keeps the user until it is finished​

onboarding is a feature with a guard of the routes. On the first launch, the app shows the onboarding in place of every other screen, whichever features it has, and it remembers in the preferences that the onboarding is finished. See onboarding.

Sign-in is screens, a session and a mode​

sign_in is the screens: the sign-in, the sign-up, the password reset and the screen of the account. firebase_auth provides the auth role under them: appSession, which knows who uses the app before the first frame, on Firebase Authentication. sign_in requires that role, so it brings firebase_auth, and firebase_core with it.

The sign-in of sign_in: the fields Email and Password, the button Sign in, and Create account below it.The screen of the account of sign_in: the address of the account, the button Sign out, and Delete account in red.

smf create asks who may use the app without an account, or takes --auth-mode: nobody (required, the default), everyone (guest), or everyone as an anonymous user (anonymous). In required the app shows the sign-in until the user is signed in. In the other two it asks for an account only on the screens that need one.

An app with sign_in needs three more things:

It needsWhyWhat to add
A state managerThe screens keep their state with it, in a variant for each. Two modules provide one, so smf create asks, or stops without a terminal.bloc or riverpod
A settings screenThe entry of the account is there. smf create adds settings by itself.nothing
A way to the settings screenA main navigation shows the settings screen among its destinations. Without one, no screen leads to it, and a screen of yours opens it or the account.bottom_tabs

An app can also have firebase_auth without sign_in: the session and the mode, with screens of your own. See Sign-in.

Guards come in the order of a first launch​

A guard of the routes has a stage, so the app asks its guards in the order of a first launch whatever the order of the modules: the onboarding comes before a guard that asks who the user is. See Guards of routes.

State management is per feature​

bloc and riverpod add their package, and riverpod also puts its ProviderScope around the app. A feature that keeps state brings its Cubits or providers in a variant for each state manager. sign_in does, so an app with it has bloc or riverpod. home and onboarding keep what moves on their screens in the screens themselves, so they work with either of them or with none.

Services work with or without a container​

The events, analytics and crash reporting roles each generate a service interface and a function that returns the app's service. With get_it, the roles register their services in the container, and features take them from there. Without a container, the app calls the function. See Services and state.

Analytics follows the router​

With a router, firebase_analytics logs a screen view for each screen the user sees. Without a router, it records only the events that the app logs itself.

Reporting modules add up​

With more than one module for crash reporting or analytics, the app's CrashReporter or AnalyticsService forwards every call to each of them on its own, so a module that fails affects no other. See Services and state.

Some useful sets​

CommandWhat you get
smf create my_appEvery question, in a terminal.
smf create my_app --no-inputOnly what every app needs: a Flutter app with a fallback start screen.
smf create my_app -m home,bottom_tabsA start screen, the router and tabs for the screens that features add.
smf create my_app -m home,settings,bottom_tabs,shared_preferencesA start screen and a settings screen as two tabs, and preferences for the settings that the app remembers.
smf create my_app -m material_theme,gen_l10n,home,settings,bottom_tabsThe same two tabs, with a light and a dark theme and the texts of the app in ARB files, in English and in Ukrainian. The settings screen has a row for the theme mode and one for the language, and the app remembers both.
smf create my_app -m home,onboarding,bottom_tabs,settings,gen_l10n,material_themeAll of that, and an onboarding on the first launch.
smf create my_app -m home,bottom_tabs,get_it,event_bus,blocA start screen with tabs, a service container, events between parts of the app, and BLoC.
smf create my_app -m home,bottom_tabs,get_it,firebase_crashlytics,firebase_analyticsCrash reports and analytics in Firebase, with screen views.
smf create my_app -m home,sign_in,bloc,bottom_tabsSign-in in front of a start screen with tabs: nobody uses the app without an account. The account is under the tab Settings, and the app signs in with Firebase Authentication.
smf create my_app -m home,sign_in,riverpod,bottom_tabs --auth-mode guestThe same screens with Riverpod, in an app that everyone may use. The sign-in opens when a user without an account taps the account under Settings.
smf create my_app -m home,onboarding,sign_in,bloc,bottom_tabs,gen_l10n,material_themeAn onboarding on the first launch, then the sign-in, with a light and a dark theme, in English and in Ukrainian. The settings screen has the rows Account, Language and Theme.
smf create my_app -m home,bottom_tabs,firebase_auth --auth-mode anonymousThe session without the screens: a start screen with tabs, and an anonymous user that the app signs in when it starts. The screens that sign a user in are yours to write.

To see what a set of modules gives before anything is generated, add --explain. It prints the modules, the roles, the dependencies and what the machine is missing, and then stops. See the smf create reference.

Conflicts​

Asking for two providers of a role that an app has at most one of, such as -m bloc,riverpod, stops smf create with a usage error that names both. Keep one of them.