Learning Flutter
Wait, what is Flutter™ ?
A framework for simultaneous publication of apps for Apple and Google Android devices
Flutter is an open source framework by Google for building beautiful, natively compiled, multi-platform applications from a single codebase.
I create mobile applications that can be published in the App Store and Google Play. I'm not a hard core developer, I have professional developers working with me in my clients and contracted work. But I am a product manager / interim CTO.
It seemed to me that going through the whole process of app creation and management and documenting it for others would be useful. I've been writing requirements and producing mobile applications for decades but I thought I'd like to learn at a far deeper level about Flutter just for fun and because cross platform applications are something I have a passion for. This is my learned experience of picking up these development tools and seeing what I can do.
Books
You might enjoy printed books. If you do then this one would be a strong pick - Flutter for Beginners: An introductory guide to building cross-platform mobile applications with Flutter 2.5 and Dart, 2nd Edition. As is Flutter Projects: A practical, project-based guide to building real-world cross-platform mobile applications and games (both on Amazon UK).

Of course, one does not simply publish an app.
In order to publish an app you have to plan, code, build, test, publish, operate, monitor, manage and update it. This is a familiar pattern these days, its sometimes called 'devops', and it can't be avoided, for if you skip elements of it then updating your app or managing it might become impossible over time. You don't want that! So while this collection of articles is based around Flutter it is also about all the surrounding disciplines that need to be considered as part of development and operating a cross platform mobile application and the inevitable platform behind it.
Flutter tech notes and demos
Building for One, Part one: a calm iPad display for someone living with dementia built a calm daily display for someone in the early stages of dementia. Building for One, Part two: what it costs to buy one command spent two days turning it into one command that ships to TestFlight and Play. Building for One, Part three: what a real iPad changeddiscovered, on a real device, how much of the design had been wrong.
This part is shorter and cheaper, and it starts with something that is meant to be a treat in build-in-public writing: a thing that worked first time.
TL;DR – A £200 Amazon Fire Max 11 tablet ran the build with no changes at all. Then we read the real screen numbers off the device, which proved a careful hedge wrong and uncovered a live layout bug in about ninety seconds. The lesson is about the guess, not the bug.
- Details
Read more: Building for One, Part four: £200 tablet just worked
Building for One, Part one: a calm iPad display for someone living with dementia built a calm daily display for someone in the early stages of dementia, and Building for One, Part four: the £200 tablet that just worked put it on a £200 tablet. In between, two parts on turning it into one command that ships to both stores and on how much of the design real tablets proved wrong. This part covers the week after that: twenty-five beta builds, and the same app sitting in three review queues at once.
Almost none of that week was spent on the thing the app does. It was spent on the fact that three different people read this app before the person it is for ever sees it (an app reviewer, a tester, and the family member doing the installing), and each of them needs different words.
TL;DR – Getting those words wrong does not produce a bug report. It produces a rejection, or worse, a person reading something about themselves that nobody meant them to read.
- Details
Read more: Building for One, Part five: everybody read it before her
Build and publish a Flutter-based app for the App Store and Google Play — updated for 2026, where Material Design 3 (also called Material You) is now the default and the tooling has moved on significantly.
2014 Baseline Material color theme
Material Design 2 was the standard and a 12-colour baseline theme was the starting point for every Flutter ap. This 2014 Baseline Material color theme made its debut with a built-in, baseline theme with 12 colours named and defined. Much has changed but these building blocks are important to understand as you think about the colours in your app.
| Primary #6200EE |
Primary Variant #3700B3 |
Secondary #03DAC6 |
Secondary Variant #018786 |
| Background #FFFFFF |
Surface #FFFFFF |
Error #B00020 |
| On Primary #FFFFFF |
On Secondary #000000 |
| On Background #000000 |
On Surface #000000 |
On Error #FFFFFF |
Material Design 3 and Material Theme Builder
That world has changed substantially. Material Design 3 is now Flutter's default theming system, and the colour model has expanded from 12 named roles to over 30, built around a dynamic, tonal palette system. The old primarySwatch and MaterialColor approach is now deprecated in favour of ColorScheme and ThemeData.colorScheme.
The tooling has changed too. The original Material Design Colour Tool at material.io has been retired. Its replacement is the Material Theme Builder, available at material-foundation.github.io/material-theme-builder/. This tool generates a complete Material 3 colour scheme — including light and dark variants — from a single source colour, and can export directly to Flutter Dart code. It is the tool you should be using today.
This article has been revised throughout to reflect these changes. The core ideas — picking colours that complement your logo, understanding colour roles, and supporting both light and dark appearance — remain just as relevant. The implementation is simply more powerful now.
TL:DR – The colours in a mobile app can look polished if you pay attention to themes and colour choices. Modern tools make it easier than ever to generate a full Material 3 colour scheme from your brand colour, and this article shows how.
- Details
Read more: Making mobile apps look better - theme and colours
Build and publish a Flutter-based app for the App Store and Google Play — revisited and updated for 2026, where dark and light appearance support is no longer optional: it is a baseline expectation for every app on every platform.
TL:DR – When this article was first written, dark mode felt like a novelty feature. That is no longer the case. Dark appearance support is no longer a nice-to-have. It is a baseline expectation on both platforms, and the tooling in Flutter has matured significantly to make it straightforward. If you are starting fresh, use Material 3 and ColorScheme.fromSeed. If you are maintaining an existing Material 2 app, plan your migration to the new type scale and colour roles. Either way, address appearance early in your design process: retrofitting it into a large codebase is genuinely painful.
- Details
Build and publish a Flutter-based app for the App Store and Google Play — updated for 2026 with current FlutterFire packages, the latest Firebase Authentication APIs, and notes on what has changed since this series began.
Let's create an authenticated end user.
TL:DR – Authentication is built into Firebase. The heavy lifting is handled for you, so you can stay focused on what makes your app unique. Now, that story is even stronger thanks to the Identity Platform upgrade and a much-improved FlutterFire SDK.
- Details
Build and publish a Flutter-based app for the App Store and Google Play — updated here for 2026 to reflect the current state of async Dart and the device_info_plus plugin.
As we dig deeper into sign-in flows, the app needs to query the device it's running on and surface relevant choices in the UI. That means working with asynchronous code — and in 2026, Dart's async story is more capable and better-tooled than ever.
TL:DR – This instalment focuses on asynchronous programming with futures, async, and await, then applies those concepts to retrieving device information inside a Flutter app.
- Details
Read more: Asynchronous programming in Flutter, futures, async, await
Building a Flutter 💙 Barcode Scanner app in 2026 — the packages worth using today, what to migrate away from, and how to get scanning fast.
The use case is straightforward: scan a collection of barcoded inventory items, persist them to a database, optionally enrich each record with product metadata from a lookup API, then expose that inventory to other services such as a web dashboard. Flutter and Firebase remain an excellent fit for this kind of cross-platform, cloud-connected workflow — and in 2026 the ecosystem around barcode scanning has matured to the point where the old default recommendation no longer holds.
TL;DR — If you are starting a new project today, skip flutter_barcode_scanner and reach straight for mobile_scanner. It is actively maintained, performs better on modern hardware, and supports every Flutter deployment target. The rest of this article explains why, shows you the code, and covers the full stack from scan to cloud.
{ToC}
What's changed in 2026
A few years ago, flutter_barcode_scanner was the obvious first recommendation for any Flutter barcode project. That is no longer true, and it is worth being direct about why before getting into implementation details.
- flutter_barcode_scanner has seen long quiet periods on GitHub. It still installs and runs on Android and iOS, but it does not support Flutter Web, macOS, Windows, or Linux, and it has not kept pace with improvements to the underlying platform ML pipelines.
- mobile_scanner has become the community-preferred package. It uses Google's ML Kit on Android and Apple's Vision framework on iOS — both of which have improved substantially in recent years — and it tracks Flutter stable with regular releases. Version 5.x, current as of 2026, introduced a cleaner API and improved Web support via the BarcodeDetector browser API with a polyfill fallback.
- Flutter itself is well into the 3.x series, with stable support for Android, iOS, Web, macOS, Windows, and Linux from a single codebase. Any package that doesn't support all six targets is increasingly a liability for teams that want deployment flexibility.
- Dart 3 is the baseline. Null safety is no longer a talking point — it is simply assumed. Packages that predate it require workarounds that are not worth carrying into new projects.
- iOS 18 and Android 15 are now the dominant platform versions in the field. Camera permission flows have been tightened on both platforms, and the Vision framework on iOS has received meaningful accuracy improvements for low-contrast and damaged barcodes.
The short version: mobile_scanner is where the momentum is. This article focuses on it, while keeping a section on flutter_barcode_scanner for teams maintaining older codebases.
The recommended approach: mobile_scanner
Add mobile_scanner to your pubspec.yaml:
dependencies:
mobile_scanner: ^5.0.0
Run flutter pub get, then drop a scanner widget into your widget tree. A minimal but fully functional implementation looks like this:
import 'package:mobile_scanner/mobile_scanner.dart';
class BarcodeScannerPage extends StatelessWidget {
const BarcodeScannerPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Scan barcode')),
body: MobileScanner(
onDetect: (capture) {
for (final barcode in capture.barcodes) {
debugPrint('Barcode found: ${barcode.rawValue}');
}
},
),
);
}
}
That is genuinely all you need to get a live scanning overlay running on Android or iOS. The MobileScanner widget handles camera lifecycle, permission state, and the ML pipeline internally. From there you can layer in additional controls as your use case demands.
Torch, zoom, and camera switching
Real-world inventory scanning often happens in warehouses or stockrooms where lighting is poor. mobile_scanner exposes torch control, zoom, and front/rear camera switching through a MobileScannerController:
class BarcodeScannerPage extends StatefulWidget {
const BarcodeScannerPage({super.key});
@override
State<BarcodeScannerPage> createState() => _BarcodeScannerPageState();
}
class _BarcodeScannerPageState extends State<BarcodeScannerPage> {
final MobileScannerController _controller = MobileScannerController(
detectionSpeed: DetectionSpeed.noDuplicates,
facing: CameraFacing.back,
torchEnabled: false,
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Scan barcode'),
actions: [
IconButton(
icon: const Icon(Icons.flashlight_on),
onPressed: () => _controller.toggleTorch(),
),
IconButton(
icon: const Icon(Icons.flip_camera_ios),
onPressed: () => _controller.switchCamera(),
),
],
),
body: MobileScanner(
controller: _controller,
onDetect: (capture) {
for (final barcode in capture.barcodes) {
debugPrint('Barcode: ${barcode.rawValue}');
}
},
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
The DetectionSpeed.noDuplicates setting is particularly useful for inventory workflows — it prevents the same barcode from firing the callback repeatedly while it stays in frame, so you don't have to debounce scans yourself.
Supported barcode formats
mobile_scanner supports all formats you are likely to encounter in an inventory context: QR Code, EAN-13, EAN-8, UPC-A, UPC-E, Code 39, Code 93, Code 128, ITF, Codabar, Data Matrix, Aztec, and PDF417. You can restrict detection to a subset of formats to improve scan speed if your use case is narrow:
final controller = MobileScannerController(
formats: [BarcodeFormat.ean13, BarcodeFormat.ean8, BarcodeFormat.code128],
);
iOS and Android platform setup
Both platforms require explicit camera permission declarations before the scanner will work.
iOS
Add a camera usage description to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to scan barcodes.</string>
On iOS 17 and later, the Vision framework's barcode detection has improved noticeably — codes that previously required deliberate slow movement are now caught on the first pass in most lighting conditions. iOS 18 tightened the permission prompt UI, so ensure your usage description is clear and user-facing; vague strings are more likely to prompt user denial.
Android
Add the camera permission to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
On Android 14 and 15, the runtime permission dialog is presented at first camera use. mobile_scanner handles the request automatically, but if you want to prompt the user before opening the scanner — for example, to explain why the camera is needed — use the permission_handler package to check and request the permission explicitly beforehand.
Enriching scan results with a product lookup API
A raw barcode value is only the starting point. For an inventory app, you want to resolve that value to a human-readable product record — name, brand, category, image — without requiring the operator to type anything. Several APIs handle this well in 2026.
- Open Food Facts API — free, open, no API key required for read access. Returns product name, brand, ingredients, nutritional data, and images. The v2 API is stable and well-documented. Ideal for food and grocery inventory.
- Barcode Lookup — broader product category coverage beyond food. Free tier available with rate limits; paid plans for higher-volume use.
- Open Product Data / GS1 — for industrial or retail supply-chain contexts where GS1-registered GTINs are in use, the GS1 registry provides authoritative product data directly from brand owners.
A Dart HTTP call to the Open Food Facts v2 API for a scanned EAN-13 confirms the approach works end-to-end:
GET https://world.openfoodfacts.org/api/v2/product/5000157062697.json
→ product_name: "Classic Cream of Mushroom Soup"
→ brands: "Campbell's"
→ quantity: "400g"
In Dart, a minimal lookup function using the http package looks like this:
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<Map<String, dynamic>?> lookupBarcode(String barcode) async {
final uri = Uri.parse(
'https://world.openfoodfacts.org/api/v2/product/$barcode.json',
);
final response = await http.get(uri);
if (response.statusCode == 200) {
final data = jsonDecode(response.body) as Map<String, dynamic>;
if (data['status'] == 1) {
return data['product'] as Map<String, dynamic>;
}
}
return null;
}
Persisting to Firebase
Saving scanned and enriched inventory items to Cloud Firestore gives you real-time sync, offline support, and a backend that any other service — a web dashboard, a reporting tool, a fulfilment system — can read from directly. The cloud_firestore Flutter plugin is mature, fully null-safe, and tracks Flutter stable.
Future<void> saveInventoryItem({
required String barcode,
required Map<String, dynamic> product,
}) async {
await FirebaseFirestore.instance.collection('inventory').add({
'barcode': barcode,
'productName': product['product_name'] ?? 'Unknown',
'brand': product['brands'] ?? 'Unknown',
'quantity': product['quantity'] ?? '',
'scannedAt': FieldValue.serverTimestamp(),
});
}
A Flutter Web dashboard reading from the same Firestore collection in real time closes the loop on the original project requirement — one scan on a mobile device, immediately visible on a browser dashboard elsewhere, with no custom backend to maintain.
For teams that prefer a non-Google backend in 2026, Supabase is a strong alternative. The supabase_flutter plugin is well-maintained and the Supabase free tier is generous for inventory-scale workloads. The integration pattern is essentially the same — replace the Firestore call with a Supabase table insert.
The older approach: flutter_barcode_scanner
For teams maintaining an existing codebase built on flutter_barcode_scanner, here is the context you need.
The package still installs cleanly on current Flutter toolchains and still works for Android and iOS targets. If your project is pinned to it and you need to ship quickly, it will not block you. The integration involves forking the repository as a precaution against upstream stalls — which, as noted, have occurred — and referencing your fork in pubspec.yaml:
dependencies:
flutter_barcode_scanner:
git:
url: https://github.com/your-username/flutter_barcode_scanner.git
ref: main
The scanning overlay and result callback work as documented. For a simple Android or iOS project with no Web or desktop requirement, it remains functional. But the migration path to mobile_scanner is not onerous — the API surface is similar enough that a motivated developer can make the switch in an afternoon — and the long-term maintenance picture strongly favours moving.
The console output for a scanned EAN-13 barcode is the same either way:
I/flutter (31686): 5000157062697
Choosing between mobile_scanner and google_mlkit_barcode_scanning
A third option worth knowing about is google_mlkit_barcode_scanning — Google's ML Kit barcode plugin for Flutter, maintained by the Google ML Kit team. It gives you direct access to the ML Kit barcode scanning pipeline without the camera widget layer that mobile_scanner includes.
Use mobile_scanner when you want a complete, ready-to-use scanning widget with camera management included — which covers the majority of inventory app use cases. Use google_mlkit_barcode_scanning when you need to process images from a source other than the device camera — for example, scanning barcodes in photos from the gallery, or processing frames from a custom camera implementation. The two packages are complementary rather than competing.
Summary
mobile_scanner is the right starting point for any new Flutter barcode project in 2026. It is actively maintained, performs well on current Android and iOS hardware, supports all six Flutter deployment targets, and requires very little boilerplate to get a working scanner in front of users. The broader stack — Firestore or Supabase for persistence, Open Food Facts or Barcode Lookup for product enrichment, Flutter Web for a real-time dashboard — is mature and well-supported.
flutter_barcode_scanner still runs on Android and iOS and is not an emergency migration if you have an existing project depending on it. But for anything new, it is the wrong starting point, and the case for migrating existing projects grows stronger as Flutter's multi-platform ambitions expand.
Scan, enrich, persist, expose. The workflow is simple. The tools in 2026 are better than they have ever been.
See also:
- mobile_scanner on pub.dev
- flutter_barcode_scanner on pub.dev
- google_mlkit_barcode_scanning on pub.dev
- supabase_flutter on pub.dev
- Open Food Facts API
- Barcode lookup — EAN 5000157062697, Classic Cream of Mushroom Soup
- permission_handler on pub.dev
- Details
Flutter development on a Chromebook
Running Android Studio, ChromeOS, and Android simultaneously on a Chromebook remains one of the more underrated development setups available in 2026. The Android subsystem is not an emulator — it is the full ChromeOS Android implementation — and when it works, it works beautifully. The landscape has shifted considerably since this workflow first became popular, so this guide has been fully updated to reflect the current state of ChromeOS development.
TL:DR – ChromeOS is still a compelling choice for Flutter development, particularly for Android-targeted work. The Google Pixelbook line has been discontinued, and Google is no longer manufacturing its own Chromebook hardware under that brand. The good news is that the ChromeOS ecosystem has matured, and there are strong alternatives from Lenovo, HP, and ASUS at a range of price points. For serious development work, you still want a machine with at least 16GB of RAM, a fast processor, and a generous SSD — cheap Chromebooks remain a poor experience for running Android Studio and the Linux container simultaneously. Do bear in mind that you cannot build for iOS or macOS on a Chromebook; you will need a Mac for those targets.
{ToC}
What's changed in 2026
The most significant shift since this article was first written is the discontinuation of the Google Pixelbook line. Google exited the first-party Chromebook hardware market, meaning the Pixelbook and Pixelbook Go are now only available second-hand. Prices on the used market have fluctuated, and while these machines remain capable, sourcing reliable units is increasingly hit-or-miss. If you already own one in good condition, it is still a perfectly usable development machine. If you are buying fresh, look at current flagship Chromebooks from Lenovo (the IdeaPad 5i Chromebook or ThinkPad C-series), HP (the Dragonfly Pro Chromebook), or ASUS (the Chromebook Plus range), all of which ship with the hardware headroom needed for Flutter development.
Flutter itself has continued to mature rapidly. The Flutter SDK is now well past version 3, with significant improvements to performance, tooling, and multi-platform support. Android Studio has moved through several major releases and is now substantially faster than before. The ChromeOS-specific Flutter documentation on flutter.dev has also improved, though the installation steps below still diverge from the official guidance in a few important ways — so follow this guide rather than the official ChromeOS page if you run into trouble.
ChromeOS itself has received ongoing updates that make the Linux container more stable and better integrated. File sharing between ChromeOS and Linux is smoother, and the Android subsystem on modern Chromebooks runs Android 13 or later, giving you access to a more current API surface for testing.
Chromebook compatibility
Checking whether your Chromebook is suitable for development is straightforward. Open ChromeOS Settings and scroll toward the bottom. If you see an Apps section with Google Play Store settings, and a Developer section where Linux can be enabled, you are good to go — provided you have sufficient disk space (64GB or more is strongly recommended). If neither option appears and cannot be enabled, the device is not suitable for this workflow and it is worth upgrading.


Recommended hardware in 2026
For new purchases, prioritise machines in the Chromebook Plus tier, which Google introduced as a quality baseline. These devices are certified to meet minimum specs that make them genuinely usable for development. Look for:
- Processor: Intel Core i5 or i7 (12th generation or later), or an AMD Ryzen 5 or 7 equivalent. Avoid ARM-only devices if you want the smoothest Android Studio experience.
- RAM: 16GB minimum. 8GB is workable but you will feel the constraint when Android Studio, the Linux container, and ChromeOS are all competing for memory.
- Storage: 256GB SSD or larger. The Linux container, Android SDK, Flutter SDK, and your projects will consume space quickly.
- Used market: If budget is a priority, a second-hand Pixelbook Go (i7, 16GB) remains a capable machine if you can find one in good condition, but verify its ChromeOS auto-update expiry date before buying — devices past their AUE date no longer receive security updates.
Installing Flutter on a Chromebook with Android Studio

This is more involved than it should be, because the instructions on the Flutter website do not fully reflect the reality of working within ChromeOS. The steps below are tested and work reliably.
- Enable Linux on your Chromebook. When prompted, allocate at least 20GB to the Linux container — more if your storage allows.
- Once Linux is running, update the system: $ sudo apt update && sudo apt upgrade.
- Download the latest stable Flutter SDK from the Flutter release archive. Because the Downloads folder is not directly visible to Linux, use the ChromeOS Files app to move the downloaded archive from Downloads into Linux files.
- Extract the SDK: $ tar xvf flutter_linux_<version>-stable.tar.xz — substitute
<version>with the filename you downloaded. - Move the
flutterfolder to a suitable location: $ sudo mv flutter /usr/local/bin. - Add Flutter to your PATH: $ echo 'export PATH="/usr/local/bin/flutter/bin:$PATH"' >> ~/.bash_profile. Restart the terminal to pick up the change.
- Run $ flutter doctor and address any flagged issues. If this Chromebook is dedicated to Android work, you can suppress other targets: $ flutter config --no-enable-linux-desktop and $ flutter config --no-enable-web.
- A healthy Flutter doctor output should look something like this:
At some point during setup you will be prompted to allow a debug connection from the Android subsystem. Accept this, and your Chromebook's Android environment will appear as a connected device.$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, on Debian GNU/Linux 12 (bookworm), locale en_US.UTF-8) [✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [✓] Android Studio (version 2024.x) [✓] Connected device (1 available) [✓] Network resources • No issues found!$ flutter devices Found 1 connected device: <Your Chromebook model> (mobile) • emulator-5554 • android-x64 • Android 13 (API 33) - Verify that the required shell tools are present: $ which bash file mkdir rm which.
- Download and install Android Studio from the official site. The site will detect ChromeOS and offer the correct
.debpackage. Current releases are in the Ladybug or later series — accept whatever the latest stable version is at the time you install. - Open the Files app, locate the
.debpackage in Downloads, right-click it, and select Install with Linux. Confirm the installation and wait — this can take several minutes.
Chromebook DEB package file — Install with Linux - Work through the Android Studio Setup Wizard. Ensure that the following SDK components are installed:
Android SDK Platform (API 35.0.0 or later),Android SDK Command-line Tools,Android SDK Build-Tools, andAndroid SDK Platform-Tools. The Command-line Tools component is frequently missed and will causeflutter doctorto complain if absent.
Ensure the Command Line Tools component is checked — it is easy to miss - Once installation is complete, launch Android Studio from the ChromeOS Launcher or directly from the terminal: $ /opt/android-studio/bin/studio.sh.
- Choose New Flutter Project, point the Flutter SDK field at
/usr/local/bin/flutter, and let Android Studio configure itself. Once the project is created, press Run. The app will build, install into the Android subsystem, and launch — just as shown in the screenshot at the top of this section.
A note on the Flutter plugin for Android Studio
In recent Android Studio releases, the Flutter and Dart plugins are managed through the JetBrains Marketplace inside Android Studio's settings rather than being bundled by default. If Android Studio does not offer you a Flutter project template on first launch, navigate to Settings → Plugins → Marketplace, search for Flutter, and install it. The Dart plugin will be installed automatically as a dependency. Restart Android Studio and the Flutter project options will appear.
It is a revelation to have Android Studio, ChromeOS and Android all running simultaneously on a Chromebook. The Android subsystem is not an emulator — it is the full ChromeOS Android implementation.
Resources
Flutter for ChromeOS — official installation guide (flutter.dev)
Flutter stable release archive
Android Studio — latest release
Enabling Linux on your Chromebook (Google Support)
Chromebook Plus — Google's current quality tier for Chromebook hardware
- Details
If you know me you'll probably know I spent a lot of time in my early career working at companies who made Spreadsheets. Naturally enough then, when I see a data set in a comma separated variable (.csv) format, I lean toward leaving it in its format and querying it. I need to use such a data set in a mobile app, so I wondered if directly getting the data from an online imported CSV was a workable strategy. This approach will likely not have some things I take for granted in Firebase but I could just host it in Google Sheets which might be worthwhile as maintenance of the .CSV would be easier and virtualy cost free if it was left alone as it just gets replaced with a new set of data from time to time.
Before you start!
The proof of concept work for this is in plain Dart. So you'll need a working local Dart environment. Flutter installs Dart, but you can also choose to install it on its own. If it works out it will need to be adjusted to work with FlutterFlow. Lets see if it fits my use case first.
TL:DR — Implementing a CSV data source for a mobile app, in Google Sheets, in Dart. how hard could it possibly be?
- Details
Cloud Firestore is a flexible, scalable NoSQL database for mobile, web, and server development. As of 2026, it remains the recommended database back end for FlutterFlow projects, and Google has continued to invest heavily in it — most notably with the arrival of an Enterprise edition in Native mode and support for multiple databases within a single project. If you are building a mobile app that needs a database back end, Cloud Firestore is still the clearest path to production.
Cloud Firestore is a NoSQL database, which means you don't define its entire structure in tables ahead of time and you don't use SQL statements to query it. Instead, you store data in collections, which contain documents, which contain fields of various types mapped to values. The supported data types are: Array, Boolean, Bytes, Date and time, Floating-point number, Geographical point, Integer, Map, Null, Reference, and Text string.
TL:DR – There is a fair amount of setup involved. You will need to configure Cloud Firestore for the Web, and to run the Firebase Local Emulator Suite you will need a Java Runtime Environment (JRE) — the quickest route on a modern Mac is via Homebrew.
- Details
Starting from a sample in Flutter — 2026 edition
Back when I first wrote this, spinning up a Flutter project with Firebase integration required a fair amount of manual configuration across every platform. In 2026, the tooling has matured considerably — Flutter 3.44 is the current stable release, the FlutterFire CLI handles most of the Firebase wiring automatically, and the flutterfire configure command has replaced the old hand-editing of platform config files for the majority of cases. That said, the core workflow of starting from a Flutter sample and layering Firebase on top remains a solid approach, so this article is worth revisiting with fresh eyes.
TL:DR – This article walks through iterating towards a Flutter app that bootstraps Firebase data for a companion FlutterFlow project. The original thinking was to keep a simple Flutter app for back-end admin work and use FlutterFlow for the prettier end-user front end. In practice, that split didn't hold up — it's easier and more maintainable to build admin functionality as role-based or user-elevated capabilities directly inside FlutterFlow. All the logic lives in one place, and you get much better adherence to DRY principles. The setup steps below are still useful if you want a standalone Flutter admin app, but go in with eyes open.
- Details
Export compliance and the App Store
When you submit an app for publication in the App Store you are uploading your app to servers located in the United States. Downloads of your app outside the United States and Canada are treated as exports from the United States — and as of 2026, U.S. Department of Commerce encryption export administration regulations (EAR) continue to apply in full. If your app uses encryption in any form, you need to understand your obligations before you ship.
TL:DR – Apps distributed via the App Store are U.S. exports. If they use encryption, they need either an export licence or a qualifying exemption. Most apps qualify for an exemption, but you still have to file an annual self-classification report with the U.S. government.
- Details