Flutter Evaluation

Status

Evaluated and rejected. This document preserves the rationale.

Context

The developer of the existing FlutterFlow app suggested staying on Flutter for the new stack. Flutter’s “one codebase, ship everywhere” value proposition is compelling for conventional teams. This evaluation explains why it doesn’t fit our specific situation.

Assumptions

The Flutter option assumes Dart/Flutter for all client apps and any suitable backend language for the server (Rust, Go, Node.js, etc.). The key architectural difference is that client business logic lives in Dart while server business logic lives in a separate language — two implementations of shared concerns like validation and scoring.

Comparison

ConcernFlutter + Separate ServerShared Rust Core + Native
UI codebaseOne (Dart/Flutter)Three (Dioxus, SwiftUI, Jetpack Compose)
Business logicDart on clients, separate language on server — two implementations of validation, scoring, data modelsRust everywhere — written once, runs on all platforms
Logic drift riskHigh — client and server implementations can diverge, bugs hide in the gapNone — same compiled code on every platform
Mobile UXGood, but not native — custom rendering engine, platform conventions approximatedBest possible — full native UI, platform conventions followed exactly
Platform APIsPlugin-dependent (camera, BLE, background sync) — quality varies, maintainer riskDirect access — no plugins, no wrappers
Web bundle sizeHeavy — Flutter web is 1.5-3+ MB minimum, poor initial load~50-70 KB WASM (Dioxus)
Web qualityFlutter web’s weakest target — accessibility issues, SEO problems, non-standard scrollingNative web with Dioxus — standard DOM, standard accessibility
OfflinePossible but business logic is in Dart, not shared with server — validation and scoring must be reimplementedCore crate runs locally — full validation and scoring offline, identical to server logic
White-label serverServer is a separate codebase with its own logic — no shared core with clientsRust server imports the same core crate — one language, one logic source
Deplatforming resilienceFlutter web PWA is the fallback, but heavy and limitedDioxus PWA is lightweight, scores offline, flushes on reconnect
Framework riskSingle dependency on Google — Flutter’s long-term commitment is a recurring concern in the communityFramework-independent — if SwiftUI or Jetpack Compose change, business logic is untouched
Shot timer (camera/BLE)Plugins — camera plugin is decent, BLE plugins have known issuesNative APIs directly — no plugin layer
Hot reloadExcellent (Flutter’s strongest feature)Subsecond (Dioxus), instant preview (SwiftUI/Compose)
Team fitOne language for UI, but business logic split between client and serverAI-assisted parallel implementation across Rust/Swift/Kotlin from a single feature description

Why Flutter Doesn’t Fit

1. Business Logic Must Exist in Two Places

Regardless of the server language, Flutter means client business logic is in Dart and server business logic is in something else. Validation rules, scoring calculations, data model constraints — all must be implemented and maintained in two languages. They will drift. The shared Rust core eliminates this entirely: one implementation compiles to server, WASM, iOS, and Android.

2. AI-Assisted Development Replaces “Write Once”

Flutter’s core value is avoiding the cost of writing UI three times. In our workflow (one developer + AI), features are described once and implemented across platforms in parallel. The cost of native UI on three platforms drops dramatically — best UX on every platform without the usual team size requirement.

3. Web Is a First-Class Target

The dashboard and PWA are critical surfaces — admin workflow and deplatforming fallback respectively. Flutter web’s large bundle size, accessibility gaps, and non-standard DOM rendering make it a poor fit for these. Dioxus compiles to ~50-70 KB WASM with standard DOM output.

4. Platform API Access Without Plugins

On-range scoring needs camera (shot timer OCR), BLE (timer pairing), and background sync (queue flush). Native apps access these directly. Flutter routes through plugins with varying quality and maintenance.

What Flutter Does Better

  • Simpler build tooling — no UniFFI, no cross-compilation, no protobuf code generation
  • One UI language — less context switching when reading UI code
  • Larger hiring pool — Flutter developers are easier to find than Rust developers (not relevant for our current team)

Decision

Flutter’s advantages are real for conventional teams but don’t outweigh the architectural benefits of shared Rust logic, native platform access, and lightweight web targets in our specific situation.