Mobile
Flutter
Google’s cross-platform toolkit that draws its own pixels — one Dart codebase, identical UI on every device. We build with it where it fits, and say so when it doesn’t.
Overview
Flutter is Google’s open-source toolkit for building applications from a single codebase written in Dart. What makes it different from most cross-platform frameworks is what it does to draw the screen: rather than wrapping the operating system’s native buttons, lists and switches, Flutter ships its own rendering engine — historically Skia, now Impeller — and paints every pixel itself. Your interface is composed from a tree of widgets that Flutter draws directly onto a canvas, which means a screen looks and behaves identically on an iPhone, an Android handset, the web and desktop, because the same code produced the same pixels on each. That is the central bargain of Flutter, and understanding it is the whole of deciding whether it suits you.
For a design-led product that wants to look exactly the way you drew it — a strong brand, bespoke components, animation that carries the experience — this is a genuine advantage. You are not fighting two platforms’ native widget sets to make them agree; you own the canvas. Flutter’s stateful hot reload also makes the build loop unusually fast: change a colour, a layout or a piece of logic and see it on the running device in under a second, with the app’s state preserved. For teams iterating on UI, that tightens the feedback loop in a way few native workflows match.
We use Flutter where that model earns its keep: brand-heavy consumer apps, products where a consistent look across iOS and Android matters more than mirroring each platform’s conventions, and teams who want one mobile codebase rather than two. We are equally clear about where it does not fit. If your product lives or dies on deep native integration, if your team is already fluent in React, or if what you actually need is a website, Flutter is the wrong tool and we will tell you so before you commit a budget to it.
Best for — Design-led mobile products that need one codebase across iOS and Android with a consistent, custom-built UI — where controlling every pixel matters more than mirroring each platform’s native look.
Why teams choose Flutter
One codebase, two platforms
A single Dart codebase produces both the iOS and Android app, so you build, test and maintain one thing rather than two. For most teams that is the whole reason to choose it — roughly half the mobile engineering surface area to own.
Pixel-identical, brand-controlled UI
Because Flutter renders its own widgets rather than wrapping native ones, your design looks the same on every device and matches the mock-up exactly. Bespoke components and custom motion are Flutter’s home ground, not a fight against the platform.
Fast iteration with hot reload
Stateful hot reload puts a code change on the running app in under a second without losing state. UI work that would be a rebuild-and-relaunch cycle elsewhere becomes a tight, immediate loop — which shows up directly in how fast the product improves.
Why businesses choose Flutter
- You want one mobile codebase across iOS and Android and value a consistent, controlled UI over mirroring each platform’s native conventions.
- Your product is design-led — a distinct brand, custom components, meaningful animation — which is exactly what Flutter’s own-rendering model does best.
- You want a fast UI iteration loop and are building a team around Dart, or hiring us to bring senior Flutter engineers who already know its sharp edges.
- You would rather be told up front when native or React Native is the better fit than be sold Flutter because it is the tool a vendor happens to like.
What we build with Flutter
The capabilities this technology is genuinely strong at — and what we most often build with it.
The widget tree and composition
Everything in Flutter is a widget — layout, padding, a button, the whole screen — composed into a tree. You build interfaces by nesting small widgets rather than configuring large ones, and understanding rebuilds, keys and the element tree beneath the widgets is how we keep a complex screen fast and predictable.
Its own rendering engine
Flutter draws every pixel through its own engine — Skia historically, now Impeller on iOS and Android — instead of delegating to native views. This is why the UI is identical across platforms and fully yours to control, and it is the single fact that most shapes what Flutter is good and bad at.
Stateful hot reload
Change code and the running app updates in place, keeping its current state — the screen you are on, the data loaded, the form half-filled. It changes how UI is built day to day, turning layout and styling work into an immediate, iterative loop rather than a rebuild cycle.
Material and Cupertino widget sets
Flutter ships two full design languages out of the box — Material for Android’s look and Cupertino for iOS’s — plus the primitives to build entirely custom design systems. We use them where platform familiarity helps and build bespoke components where the brand demands it.
Platform channels to native code
When Flutter needs something the framework does not cover — a specific native SDK, a hardware feature, a bleeding-edge OS API — platform channels bridge Dart to Kotlin/Java on Android and Swift/Objective-C on iOS. We are comfortable writing this native glue, and honest that needing it is part of the real cost of Flutter.
Ahead-of-time native compilation
Release builds compile Dart ahead-of-time to native ARM machine code rather than shipping an interpreter, which is why Flutter performs close to native for most apps. In development it uses a just-in-time compiler to enable hot reload — the two-mode model that gives you both fast iteration and fast releases.
Use cases
Brand-led consumer apps
Products where the interface is the brand — custom components, distinctive motion, a look that must be identical on every device. Owning the canvas rather than negotiating with two native widget sets is exactly where Flutter is strongest.
Cross-platform MVPs
When a startup needs iOS and Android from day one on one budget and one team, a single Dart codebase and fast hot-reload loop get a credible app in front of users quickly — without funding two separate native builds.
Internal and field tools
Line-of-business apps for staff — inspections, logistics, point-of-sale, data capture — where a consistent UI across whatever devices the team carries matters more than matching each platform’s native conventions.
Content and commerce apps
Media, catalogue and storefront apps that are largely custom UI over an API, where design consistency and quick iteration count and there is little dependence on deep platform-specific native features.
When Flutter is the right choice
- Right when you want one codebase serving iOS and Android with a genuinely identical, brand-controlled UI — Flutter draws its own widgets, so the two platforms match pixel for pixel
- Right for design-led and animation-heavy products where you want the interface to look exactly as designed rather than adopt each platform’s native components
- Right when a fast UI iteration loop matters — stateful hot reload makes building and refining screens quicker than most native workflows
- Wrong when the product depends on deep, platform-specific native integration or brand-new OS features — you will spend your time writing platform channels to bridge into native code
- Wrong when the team is already React-skilled (React Native reuses that knowledge), or when you actually need a content website — Flutter is an app toolkit, not a web-page tool
Flutter: pros and cons
Strengths
- A single Dart codebase targets iOS and Android (and web and desktop) with one team, one toolchain and one set of tests to maintain.
- Its own rendering engine gives pixel-identical UI across platforms and total control over custom, brand-heavy designs and animation.
- Stateful hot reload makes the build-and-refine loop genuinely fast, which is where much of the day-to-day productivity gain lives.
- Compiles ahead-of-time to native ARM code for release builds, so performance is close to native for the great majority of apps.
Trade-offs
- Dart is a niche language with a smaller talent pool than JavaScript or Kotlin/Swift, so hiring and handover are harder and a real planning factor.
- Because it does not use native widgets, a Flutter app can feel subtly non-native in places, and it lags brand-new OS UI features until the framework catches up.
- Binaries are larger than equivalent native apps — Flutter bundles its own engine — and platform gaps mean writing platform channels into native code more often than teams expect.
- The web and desktop targets are markedly less mature than mobile; treat them as bonuses, not as reasons to choose Flutter for a website or a serious desktop app.
Architecture
Flutter gives you a widget tree and very little opinion about anything above it, so the architecture is where a project is won or lost — much as it is with React. The load-bearing decisions we settle early are state management, the boundary between UI and business logic, and how the app talks to its data. Flutter’s ecosystem offers several state approaches — Riverpod, Bloc, Provider — and the right one depends on the app’s complexity rather than fashion. We keep widgets focused on rendering and push logic into a testable layer beneath, so the UI stays a thin, replaceable surface over the real behaviour.
Beneath that sits the reality that Flutter does not cover every platform capability itself. Where the app needs native SDKs, hardware access or an OS feature the framework has not reached, we design a clean boundary — a repository or service interface in Dart, with platform channels behind it — so the native glue is contained and swappable rather than smeared through the UI. Getting that boundary right early is what keeps the codebase honest as platform-specific requirements accumulate, because they always do.
Performance
Flutter compiles ahead-of-time to native machine code for release, and for the overwhelming majority of apps it performs close to native — smooth scrolling, responsive input, animation that holds its frame rate. The performance problems that do arise are specific and predictable: rebuilding too much of the widget tree on every state change, expensive work done during a build, oversized images, and janky first frames. We profile with Flutter’s DevTools rather than guessing, then fix the actual cause — narrowing rebuild scope, using const constructors, and keeping heavy work off the UI thread.
The move from Skia to the Impeller engine has closed much of the historical gap around shader compilation stutter, particularly on iOS. We are honest about the remaining costs, though: app binaries are larger than native because Flutter ships its own engine, and the very first frame after launch does more work than a native app’s. Where startup time or install size genuinely matters for your users, we measure it and treat it as a real constraint rather than pretending the trade-off does not exist.
Security
A Flutter app is a client, and the first rule of client security applies unchanged: never trust it. Authentication and authorisation are enforced on the server, secrets never live in the shipped binary — Dart code can be decompiled like any other — and sensitive values go through the platform’s secure storage, the iOS Keychain and Android Keystore, rather than plain preferences. We treat certificate handling, token storage and secure API communication as deliberate decisions, not defaults inherited from a starter template.
Because Flutter leans on packages from the pub.dev ecosystem, every third-party dependency is attack surface, and some plugins wrap native code that warrants a closer look. We keep the dependency tree small and current, watch for known vulnerabilities, and pay particular attention to anything touching payments, credentials or personal data. On regulated work we build with UK GDPR and data-minimisation in mind from the first screen rather than retrofitting it after a review.
Scalability
For a mobile app, scaling is mostly about the codebase and the team rather than raw traffic — the load lands on your backend, not the handset. Flutter scales well on that axis when the architecture is disciplined: clear separation between UI and logic, a consistent state-management approach, a shared component library, and Dart’s sound type system catching whole classes of error at compile time. That is what lets several engineers work in one codebase, and one product grow across iOS and Android, without it fragmenting.
The honest constraint on scaling a Flutter team is the talent pool. Dart is a smaller world than JavaScript or the native languages, so hiring takes longer and handover needs care. We plan for that deliberately — readable, well-structured code, real documentation on the load-bearing paths, and a native glue layer kept small enough that a new engineer can understand the whole system rather than just the Dart on top of it.
Flutter integrations & ecosystem
The technologies we most often pair with it — each links to how we work with it.
How we work
We start by settling the decisions Flutter leaves open — state management, the UI-to-logic boundary, and where native code will be needed — because these are cheap to get right early and expensive to unpick later. Then we build in thin vertical slices: one real feature, working end to end on a real device, rather than a scaffold that looks finished but does nothing. Flutter’s hot reload makes this loop fast, and we use it to refine UI against reality rather than a static mock-up.
The engineers who design the app are the ones who write it and keep it running on the stores. That is what we mean by operating what we build — decisions are made by people who will live with the maintenance reality, so we favour durable choices over whatever the ecosystem is excited about this quarter. You get typed Dart, honest trade-offs about where native code was necessary, and an app your own team can pick up and extend.
The service behind it
Delivered throughMobile App DevelopmentWhat we build with Flutter
The disciplines this technology most often shows up in — from a first build to taking over and stabilising an existing one.
How we deliver
- 01
Discover
We map the system, the constraints and the business it serves — including the parts nobody documented.
Architecture brief
- 02
Architect
Decisions get made, written down and defended before a line of production code exists.
Decision records
- 03
Build
Short cycles against working software. You see progress in the product, not in a status deck.
Shipping increments
- 04
Operate
Monitoring, incident response and iteration. The system is alive, so the engagement is too.
Runbooks & SLOs
Industries we use Flutter in
Domain knowledge changes what gets built. A few of the sectors we know before the first meeting.
Also in Mobile
Why teams choose us for Flutter
Senior engineers only
Flutter’s sharp edges — rebuild scope, platform channels, engine-level performance — reward experience and punish guesswork. The people making your decisions have shipped Flutter before and seen how it ages. No juniors learning on your project.
We operate what we build
We run the apps we ship through their store lives, so we optimise for the eighteen-month maintenance reality, not the demo. That means a contained native layer, conservative package choices, and code your team can actually maintain.
Honest about when not to use Flutter
If your product needs deep native integration, if your team is React-skilled and React Native fits better, or if you actually need a website, we will say so before you spend money — even if that means we do not win the build.
Typical timeline
- 01
Discovery and architecture
One to two weeks agreeing the screens, state-management approach, data flow and any native integration, so the foundations are settled before the codebase grows.
- 02
First vertical slice
Two to three weeks delivering one real feature end to end on a device, proving the architecture — and any platform-channel work — against reality rather than a plan.
- 03
Iterative build
Feature-by-feature delivery in short cycles, each running on both platforms, with performance and platform differences checked as we go rather than left to the end.
- 04
Store release and handover
App Store and Play Store submission, final profiling with DevTools, tests on the load-bearing paths, and documentation so your team can own and extend the app.
How pricing works
- Fixed-scope builds for well-defined apps — a specific product with clear features and acceptance criteria — quoted once we understand the screens, the data and any native integration needed.
- Monthly senior engagement for ongoing product work, where scope evolves across releases and you want continuity rather than a fixed deliverable.
- Focused audits and rescues for existing Flutter codebases — performance, architecture, or a stalled build — priced by the assessment.
Hire Flutter engineers
Need Flutter capacity on your own team? We embed named senior engineers into your existing team — reporting to your leads, working in your rituals — so you add capacity without a hiring cycle.
Hire Flutter engineersCommon questions
Flutter or React Native — which should we choose?
It comes down to two honest differences. Flutter draws its own widgets with its own engine, so the UI is pixel-identical across platforms and fully yours to control, and it uses Dart. React Native uses the actual native components and JavaScript/React. If your product is design-led and you want total UI control, Flutter tends to win. If your team already knows React, or you want a more native feel and a far larger talent pool, React Native is often the better fit. We will make the call on your specifics rather than on which we prefer.
Does a Flutter app feel native?
Mostly, but not perfectly, and it is fair to know why. Because Flutter draws its own widgets rather than using the platform’s, an app can feel subtly non-native in places, and it lags brand-new OS UI features until the framework catches up. For a strongly branded, custom-designed app that is usually irrelevant — the design is the point. For an app that must feel exactly like a stock iOS or Android app, native or React Native may serve you better, and we will say so.
Do we need to hire Dart developers?
Eventually, if you want to own the codebase in-house, yes — Flutter is written in Dart and there is no way around that. Dart is a smaller talent pool than JavaScript or the native languages, so hiring takes longer and is worth planning for. That constraint is a genuine factor in choosing Flutter, and we are upfront about it. In the meantime we write readable, well-documented Dart specifically so handover to a new team is manageable rather than painful.
Can Flutter access native device features?
Yes. Common features — camera, location, notifications, secure storage — are covered by well-maintained plugins. When you need something the ecosystem does not cover, or a bleeding-edge OS API, platform channels bridge Dart into native Kotlin/Swift code, and we are comfortable writing that glue. The honest caveat is that needing platform channels is more frequent than teams expect, and it is part of the real cost of Flutter that we factor into any estimate.
Should we use Flutter for our website?
No. Flutter can target the web, but that support is far less mature than mobile, the output is heavy, and it is poor for content and search engines because it does not produce ordinary HTML pages. Flutter is an app toolkit, not a website tool. If you need a marketing site or a content platform, we would build that with the right web technology and, if you also need a mobile app, use Flutter for the app — not stretch one tool across both jobs.
Building on Flutter?
A technical conversation with the engineers who would do the work. If we are not the right fit, we will say so on the call.