Build FlutterFlow
KINDAreplaces $39/mosaves $468/yrback to the verdict
A Flutter application built from a schema you define once: generated data models, a real authentication flow, list and detail and edit screens per entity, an offline cache that survives a train tunnel, and signed builds distributed to testers on both platforms.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why The framework. The doctor also tells you which platform toolchains are missing before you waste time.
Get it Install from flutter.dev following the guide for your operating system, then run the doctor and resolve every warning for your targets. open ↗
Verify
flutter doctor reports no issues for your intended platforms - have readyfree if you have one
Why Emulators hide performance, permissions and offline behaviour, which are three of the five things this build is about.
Get it Any recent Android device with developer options and USB debugging enabled.
Verify
flutter devices lists it and flutter run installs to it - have readyfree if you own a Mac; otherwise this is the largest cost in the project
Why There is no supported way to build or sign an iOS application without macOS. This decides your platform scope.
Get it Any Mac able to run a current Xcode. If you do not have one, decide in Phase 1 that this is Android only.
Verify
A Flutter application runs on a physical iPhone - account99 USD per year
Why Required to install on devices you do not own and to use the testing distribution channel.
Get it Enrol at developer.apple.com/programs. Review can take several days, so start early if iOS is in scope. open ↗
Verify
A provisioning profile installs a build on a tester's device - account25 USD one time, plus identity verification
Why Needed for the Android testing channel and any public listing.
Get it Register at the Play Console. There is a one-time fee and an identity verification step that takes time.
Verify
An internal testing release reaches a tester - accountfree tier available for managed; self-hosting costs a server
Why Provides the database, authentication and API. Without it Phase 3 has nothing to talk to.
Get it Create a project at supabase.com, or run the Docker stack yourself. Take the project URL and the anon key.
Verify
A query from the application returns rows
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- The worked example is a field inspection application. Replace these with your own entities in Phase 2 and keep the shape. - schema.yaml · your entities, fields, types and relations, the single input to code generation - sites(id, name, address, lat, lng, created_at) - inspections(id, site_id, inspector_id, state, started_at, submitted_at, notes) - findings(id, inspection_id, severity, description, photo_path, recorded_at) - sync_queue(id, entity, entity_id, op, payload_json, attempts, last_error) · the outbox that makes offline work
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
SUPABASE_URL | required | https://yourproject.supabase.co | Your project settings. Public by design. |
SUPABASE_ANON_KEY | required | eyJhbGciOi... | Project API settings. Safe in the client only because row level security is doing the work. |
ANDROID_KEYSTORE_PATHsecret | optional | ./keys/upload.jks | Product phase only. Never committed. Back it up in two separate places. |
ANDROID_KEY_ALIAS | optional | upload | The alias used when the keystore was created. |
ANDROID_KEY_PASSWORDsecret | optional | replace-with-your-password | Kept in a password manager, never in the repository. |
SYNC_MAX_ATTEMPTS | required | 8 | How many times a queued write retries before being marked failed and shown to the user. |
The build, in order
Toolchain, and the distribution decision
A Flutter application runs on a real device on each platform you intend to ship to.
Install the SDK, then resolve every doctor warning for your targets. Ignoring them now means debugging them later with more code in the way.
terminalflutter doctor -v flutter create fieldapp
Emulators hide performance and permission behaviour. Use a real device from the first day.
terminalflutter devices flutter run -d <device-id>
This requires Xcode, a signing identity and a provisioning profile. It is the single most likely thing to block you, so do it before writing code.
done when · tick each as it passeswatch out- Building for iOS requires macOS and Xcode, and distributing to testers requires a paid Apple Developer account before you can install on a device you do not own. If you do not have a Mac, decide now whether this is an Android-only application, because discovering it in Phase 6 wastes the work.
Schema and generated models
One schema file produces your data models, and changing it regenerates them.
Entities with fields, types, nullability and relations. This file is the thing you maintain; everything else follows from it.
Files
schema.yamlA build step producing serialisable model classes and Drift table definitions. Run it as part of the build so it cannot be forgotten.
Files
lib/generated/terminaldart run build_runner build --delete-conflicting-outputs
A schema change must produce a migration. Without it, the local database and the models diverge and the failure appears as mysterious query errors.
Files
lib/db/migrations/
done when · tick each as it passeswatch out- Hand-editing generated files is the habit that destroys the value of generation, because the next run silently discards the edit. Keep generated files clearly marked, never edit them, and put anything custom in a separate file that extends rather than modifies.
Authentication and the data source
A real person can sign in, and the data they see is the data they are allowed to see.
Sign in, sign out, and token refresh. Store the token in secure storage, not in shared preferences.
Files
lib/auth/One policy per table, on the server. This is the actual access control and everything else is presentation.
Files
supabase/policies.sqlUse a request tool with a second user's token and confirm the refusal. Testing through your own client proves nothing.
done when · tick each as it passeswatch out- Filtering by user in the client is not access control; anyone can call the API directly with the same token. Put the rule in a row level security policy, then verify by querying the API with a second user's token and confirming the refusal.
Generated screens
Each entity has list, detail and edit screens, generated from the schema and then refined by hand.
A one-off generator writing into the normal source tree, not into the generated directory. Different rules for different kinds of code.
Files
tool/gen_screens.dartRequired, type and length come from the field definitions, so validation cannot drift from the database.
Files
lib/forms/Change a generated screen, regenerate models, and confirm the change survives.
done when · tick each as it passeswatch out- Screens are where design judgement lives, so continuously regenerating them destroys every refinement you make. Generate screens once as a scaffold you then own, and keep continuous regeneration for models and migrations where there is no judgement to lose.
Working offline
The application is usable with no signal, and nothing entered is lost when the network returns.
The network fills the cache; the interface never waits on it. This inverts the usual structure and is the whole of offline support.
Files
lib/repository/Queue writes with attempts and last error. Exponential backoff, and a cap after which it is marked failed rather than retried forever.
Files
lib/sync/outbox.dartPer record: synced, pending or failed. Not a global spinner, which tells the user nothing about their record.
Files
lib/widgets/sync_badge.dart
done when · tick each as it passeswatch out- An optimistic write with no visible pending state makes the user believe the data is safe when it exists only on their phone. Show pending and failed states plainly, because the moment that matters is when someone closes the application believing their work was submitted.
Signing, builds and testersproduct builder
Real testers install it on their own phones, and you can still ship an update in a year.
Generate the Android keystore, then copy it to two separate durable locations before you use it. Record where they are.
Files
docs/release.mdterminalkeytool -genkey -v -keystore upload.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
One script producing signed artefacts for each target, so a release does not depend on remembering flags.
Files
scripts/release.shterminalflutter build appbundle --release
Use the platform testing channels. Installing on a device you do not own is the test that signing is genuinely correct.
done when · tick each as it passeswatch out- Losing the Android upload keystore means you can never update that listing again under the same identifier. Back it up in at least two places outside the build machine before your first release, and record where. This is not recoverable by support in the general case.
That is the whole plan for FlutterFlow. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The visual editor and the collaboration it enables for non-developers.
- The prebuilt integration catalogue.
- Managed builds and store submission handling.
- The design polish that comes from a canvas and a component library.
- visual editor depth, native builds, integrations, collaboration, and code generation
- hundreds of connectors
- pixel-perfect app design
- mobile app-store builds
- enterprise permissions and scale
- Push notifications, which need platform credentials and a delivery service
- Conflict resolution beyond last write wins, once two people edit the same record
- A web build from the same codebase, which Flutter supports and which is nearly free here
Need the files? The project pack on the verdict page hands your agent the whole brief · more no-code apps.