A Closer Look at Flutter Project Templates

Flutter is an excellent cross-platform UI-toolkit written in Dart. It comes with a great set of tools to help build your Flutter projects, including the Flutter CLI. Most people think of Flutter as a way to build new cross-platform mobile applications. So why does the flutter create command have four different project templates to choose from?

Here’s a look at each Flutter project template (app, package, plugin, and module) and how you can use them in your next Flutter project.

Flutter App

Flutter app compilation targets
Flutter apps support iOS, Android, Web, and Desktop.

A Flutter app project template is the most common since it’s the default when running flutter create. This creates a project template with all the necessary infrastructure to build/run a Flutter app. Depending on which platforms you’re planning to target, it will bootstrap all the necessary files for ios, Android, Windows, macOS, Linux, and web on your behalf. You can specify which platforms you want to target with the --platforms command-line argument.

A Flutter app project can run the flutter build command to package the Flutter app into the corresponding platform’s file type. For example, if you’re building the iOS app, it will precompile all of the Dart code in the project and bundle it up into an .ipa file that you can upload for distribution.

Flutter apps also rely on several packages and plugins as dependencies. These add new functionality or interact with platform-specific features. So let’s take a look at those project templates.

Flutter Package

You can add Flutter packages as a dependency to all other Flutter project types.
You can add Flutter packages as a dependency to all other Flutter project types.

A Flutter package project is essentially that, a package. Packages only contain Dart code that should be shared with other projects, unlike plugins, which we’ll look at shortly. A Flutter package should be straightforward to understand if you’re familiar with packages from other languages (like NPM, NuGet, RubyGems, etc.).

Technically, unless the package relies on the Flutter framework as a dependency, it’s no different than a Dart package. That means you can also build a package that works for other Dart projects as well. Packages are added as dependencies to other Flutter projects, including apps, plugins, modules, and even other packages.

Flutter Plugin

Flutter plugins use Platform Channels to communicate with the native platform.
Flutter plugins use Platform Channels to communicate with the native platform.

Flutter plugins are similar to packages in that you add them as dependencies to other projects. But there is one key difference. Unlike packages, Flutter plugins can call into the native platforms to access platform-specific functionality. For example, if your app needs to access the device camera, you’ll need to add a plugin as a dependency rather than a package.

A mechanism called Platform Channels makes this possible. Conceptually, a platform channel consists of two parts: a Dart side and the native side. The Flutter app calls into the provided Dart methods from the plugin to send an encoded message down into the native side (Swift/ObjC for iOS, Java/Kotlin for Android). Then the native side reads the message, uses any platform-specific functionality it needs to, and responds with any information it has.

Platform channels are quite interesting, and I highly suggest reading about them.

Flutter Module

Flutter modules are packaged up and embedded into native apps.
Flutter modules are packaged up and embedded into native apps.

Last but not least are Flutter modules, which are definitely the hardest to reason about. It’s similar to a Flutter app project in the sense that you’re using Flutter to build a UI. However, the goal is not to build a standalone mobile app. Flutter modules are intended to be added to existing native applications.

Using the flutter build command, you can compile a Flutter module into a XCFramework or Android Archive (AAR). You can then embed the module into a native app with the intent of rendering a Flutter UI from within the native application. This is particularly useful if the desired UI for a new section of the app is tricky to implement on both platforms consistently. You can build it once as a Flutter module and then share it between the native iOS and Android apps.

Flutter Project Templates: Putting It All Together

Now that you know a little bit more about each of the Flutter project templates, you can use them more effectively!

Need to share some Widgets between your Flutter App and your Flutter Module? Move those Widgets into a Flutter package that you can add as a dependency to the Flutter App and Flutter Module. Want to add a Flutter Module to an existing native app that needs Bluetooth LE capabilities? Add a Flutter Plugin for Bluetooth LE support as a dependency to your Flutter Module.

I’ve found some creative ways to use these Flutter project templates, but I would love to hear some of yours if you’re willing to share!