All work
01App2026

A regional grocery chain

A Flutter shopping app rebuilt from two diverging native codebases into one, shipping to iOS and Android on the same day.

Engagement
18 weeks
Year
2026
Disciplines
App Dev · UI/UX · Backend
Feature parity gap
6 weeks → 0 releases

The problem

The client ran separate Swift and Kotlin apps built by different contractors two years apart. The iOS app was six weeks ahead on features and the Android app had a checkout flow nobody could explain; every product decision had to be specified, built and QA'd twice, and roughly 60% of their mobile budget was going into keeping the two in step rather than into anything a customer would notice.

What we did

  1. 01

    Prove the hard screen first

    Before committing to a rewrite we built one screen in Flutter — the basket, which carries live pricing, substitutions and a delivery-slot picker, and was the most animation-heavy thing in either app. Two weeks, both platforms, running on real devices in their office. That screen is what made the decision, rather than a slide comparing frameworks.

  2. 02

    Migrate by flow, not by rewrite

    Flutter was embedded into the existing native apps and flows were replaced one at a time behind the same navigation. Browse went first, then basket, then checkout. Every one of those was a normal release with a rollback path — at no point was there a big-bang cutover, and the store listing never changed.

  3. 03

    One design system, drawn once

    Flutter renders its own widgets rather than delegating to UIKit and Material, so the design system is a single set of Dart components and the two platforms cannot drift. Their designer stopped maintaining two Figma libraries in the second month.

  4. 04

    60fps as a build gate, not an aspiration

    Frame timings from integration tests run on physical devices in CI, and a regression past 16ms on the scroll-heavy screens fails the build. Cross-platform frameworks earn their reputation for jank when nobody measures; this is the check that stops it becoming true.

What changed

Both platforms have shipped from one codebase and one release train since week fourteen. The team that was maintaining two apps now builds features, and the first thing they used the recovered capacity for was the recipe-to-basket flow that had been on the roadmap for a year.

Codebases maintained
21
Feature parity gap
6 weeks0 releases
Median release cycle
5 weeks9 days
Crash-free sessions
98.1%99.7%
App Store rating
3.84.6

Built with

  • Flutter
  • Dart
  • Riverpod
  • Firebase
  • Node.js
  • Fastlane

They built our worst screen in two weeks and handed us a phone. That was the entire business case — we stopped arguing about frameworks and started arguing about the basket, which is the argument worth having.

Head of DigitalRegional grocery chain

Have a problem shaped like this one?

Start a project