This is not a benchmark post. There are no multipliers, no “X% faster than” charts, no synthetic frame-time graphs. It is a first-hand account of a decision our studio actually lives with every day: we build our games on Flutter, with Flame as the game layer on top of it. We are happy with that choice most of the time and occasionally irritated by it, and both of those feelings are useful information for anyone weighing the same stack. What follows is the reasoning, told plainly, and then the places where the seams show.
One codebase, three targets — and we mean it
The headline reason is the boring one, and it is still the right one: a single Dart codebase compiles to iOS, Android, and the web, and for the most part it behaves the same on all three. That sentence is easy to write and hard to believe until you have shipped on a stack where it was not true — where “cross-platform” meant a shared core plus two piles of per-platform glue that drifted apart the moment you stopped looking. With Flutter, the rendering is ours, not the platform’s: the framework paints every pixel itself rather than delegating to native UI widgets. A button looks like our button on an iPhone, on a mid-range Android device, and in a desktop browser tab, because the same code drew it in all three places. For a small studio, that is not a convenience. It is the difference between maintaining one game and maintaining three that happen to share a name.
The corollary matters just as much: our mental model is unified. When a bug reproduces on Android, we are almost always debugging the same Dart that runs on iOS, so the fix lands everywhere at once. We are not context-switching between Swift, Kotlin, and a scripting layer; we are reading one language, one widget tree, one state model. That single-model discipline is what lets a very small team keep several titles alive in parallel without the maintenance load compounding into paralysis.
Fast iteration is a feature, not a nicety
The second reason is iteration speed, and here Flutter earns its reputation. Stateful hot reload — push a code change and see it in the running app in a moment, without losing the current screen or game state — changes how you work. You stop batching changes into big scary commits and start having a conversation with the running game: nudge a value, watch it, nudge it again. For the kind of games we make, where feel is everything and feel is only discoverable by playing, that tight loop is worth more than any raw performance headline. The stuff that makes a mechanic feel alive — the easing curve, the timing of a bounce, the delay before a reward lands — is exactly the stuff you tune by feel, over and over, and a slow edit-build-run cycle quietly taxes every one of those iterations. (We wrote a whole piece on that craft in the anatomy of game juice; the short version is that the loop is where the polish comes from.)
The widget model, and why Flame sits so well on it
Flutter’s core idea is that the UI is a function of state: describe what the screen should look like for a given state, and the framework figures out the minimal set of changes to get there. Everything is a widget — a composable, declarative building block — and you assemble screens by nesting them. For the non-game scaffolding around our titles (menus, settings, store screens, onboarding, the paywall, the leaderboard), that model is a genuine pleasure. It is the same toolkit a serious app team would use, which means our game menus are not a second-class hand-rolled UI; they are real, accessible, themeable Flutter.
Flame is the piece that makes this a game
engine rather than an app framework with delusions. It is a lightweight 2D engine that
lives inside a Flutter widget — the game renders into a
GameWidget that you drop into the widget tree like any other. That
architecture is the whole trick: the game world runs on Flame’s own loop and
component system, while the surrounding chrome stays plain Flutter, and the two share one
runtime. Flame gives us the things a 2D engine must: a game loop that
ticks every frame with an update(dt) pass for logic and a
render(canvas) pass for drawing; a component system where
the world is a tree of components (sprites, hitboxes, effects, the player, enemies) each
owning its own update and render; plus sprite and animation handling, a camera and
viewport, collision detection, an effects/tween system, and input and audio hooks. It is
deliberately not a kitchen sink. It gives you the loop and the scene graph and gets out
of the way, which suits a team that would rather write its own game logic than fight an
opinionated editor.
The tooling around all of this is the quiet third pillar. The Dart toolchain is genuinely good: a fast analyzer that catches mistakes as you type, a first-class formatter so nobody argues about style, a real package ecosystem for the non-game parts (networking, storage, ads, analytics, in-app purchase), and a testing story that lets us pump widgets and simulate frames in CI-free local runs. Because the whole thing is code, it fits how we actually work — version-controlled, reviewable, automatable — rather than living in a binary project file that resists diffing.
Where it breaks down
Now the honest half, because a framework you only praise is a framework you have not shipped on. The first and most fundamental limit is dimensionality. Flame is a 2D engine. There are community efforts and clever tricks to fake depth, and Flutter itself can host 3D through separate packages, but none of that turns this stack into a home for heavy real-time 3D. If your game is a photoreal open world, a physics-dense shooter, or anything that leans on a modern rendering pipeline with lighting, shadows, and thousands of draw calls, you are fighting the tool, and you should not. That is not a knock on Flame; it is a category boundary. We build polished 2D, and inside that box the ceiling is high. Step outside it and the ceiling is right above your head.
The second limit is the ecosystem gap against the incumbents. Choosing Flame means choosing a smaller world than Unity or Unreal. Those engines have marketplaces overflowing with ready-made assets, plugins, shaders, and behaviours; a deep bench of hireable developers; and an answer for almost any “how do I” question already written down somewhere. Flame’s ecosystem is real and friendly, but it is thinner. More often than on a mainstream engine, the answer to “is there a package for this?” is “no, you will write it,” and you should price that in. For us it is usually an acceptable trade — we like owning our game logic — but if your plan depends on buying a behaviour off a shelf, the shelf is smaller here.
Platform quirks are the third. “Write once, run everywhere” is true right up until it is not, and the exceptions cluster exactly where you would expect: audio latency and mixing behave differently across devices; in-app purchase, ads, and platform login are per-store integrations no matter how unified your Dart is; safe-area insets, notches, back-gesture handling, and haptics each have their own personalities. None of these is fatal, and most are a known, well-trodden fix, but they are real work that the “one codebase” pitch quietly omits. Budget for a platform pass; do not believe you have escaped platforms entirely.
The fourth is the one that costs us the most sleep: the web build. Getting a Flutter/Flame game running in a browser tab is genuinely possible — it is one of the reasons we chose the stack — but the web target carries a different set of constraints than mobile. Initial download size is larger than a hand-tuned native web game, first paint takes longer because a runtime has to load before anything draws, and the rendering path in the browser has historically had its own performance character that does not always match what you see on a phone. The gap has been closing as the browser rendering story matures toward newer graphics APIs, but if the web is your primary platform rather than a bonus surface, this is the area to prototype first and trust least. We are writing that whole story up separately in Shipping web games in 2026, which digs into WebGL, WebGPU, and the realities of Flutter-to-browser builds; treat this paragraph as the trailer.
So when would we pick something else? Without hesitation: for high-fidelity 3D or a physics-heavy real-time game, we would reach for Unreal or Unity, because that is what they are for. For a browser-first game where download size and instant load are the whole product, we would look hard at a web-native engine before committing Flutter to the job. And if a project’s success hinged on hiring a large team fast or leaning on a huge asset marketplace, the ecosystem depth of a mainstream engine would outweigh the elegance of ours. We laid out that whole comparison — Unity against Godot, Unreal, GameMaker, Bevy, Flame, Cocos, and the rest — in Unity vs the alternatives in 2026, and the punchline there is the same as here: the right engine is the one that fits your game’s dimension, platforms, language, and risk tolerance, not the one that tops a chart.
Who this is (and isn’t) for
Flutter and Flame are for the team that ships polished 2D, values a tight iteration loop over raw rendering ceiling, wants one codebase and one mental model across mobile (and, with eyes open, the web), and is comfortable writing its own game logic rather than assembling it from a marketplace. If you are a small studio or a solo developer who also cares about the app-shaped parts of a game — the menus, the store, the settings, the accessibility — being first-class rather than an afterthought, this stack will feel like it was built for you, because in a sense it was.
It is not for the 3D-forward team, the studio whose plan depends on off-the-shelf assets and a large hireable talent pool, or the project where the browser is the primary platform and every kilobyte and millisecond of first paint is sacred. Those are real games with real needs, and pretending our favourite tool serves them would be exactly the kind of dishonesty this blog exists to avoid. We chose Flame not because it wins a popularity contest — it wins none — but because it is the right tool for the games in our catalogue. If your games look like ours, it may well be the right tool for you. If they do not, the most useful thing this post can do is send you cheerfully elsewhere.
Notes
This is a first-hand engineering account, not a benchmark study. Every judgement here — on iteration speed, ecosystem depth, platform quirks, and web-build behaviour — is qualitative and drawn from our own experience shipping on this stack. We have deliberately included no performance multipliers, percentages, or synthetic frame-time numbers, because we did not run a controlled study to produce them and we will not invent them. Where a claim is genuinely comparative — “heavier than a native web game,” “thinner ecosystem than Unity” — read it as a practitioner’s directional judgement, not a measured result. For the framework and engine themselves, the primary references are the Flutter and Flame project sites. For the wider engine-choice reasoning that this post assumes, see the companion piece Unity vs the alternatives in 2026.
Keep reading: all posts on the WizusLabs Engineering blog.