Flutter Beyond Mobile — Building a Full-Stack Product 100% in Dart
Lessons from building Table Online: a real-time multiplayer game, admin dashboard and backend, all written in Dart. Why ‘Flutter = mobile’ is a limitation we outgrew with a small team.
On April 24, 2026 I gave a talk at PeakIT 008 in Brașov on a topic that has been on my mind for a few years: why do we limit Flutter to mobile apps? This article is the written version of the same thesis, plus a few details that did not fit in a 30-minute slot.
Personal context — 16 years of mobile
I started writing iOS code in 2010, before iPads had retina screens. Vienna (forfone, VoIP app), Düsseldorf (Secusmart/BlackBerry, security-grade mobile), then in 2021 I joined IDT Corporation where I lead the migration of native apps onto Flutter. In parallel, since 2023, I am CEO at TAGonSoft, where we build Flutter products end-to-end — including table-online.ro, the multiplayer backgammon game I used as the case study in the talk.
I mention this not to brag but to set context: I did not jump on Flutter because I could not do native. I have deep respect for native; I shipped code that could not be compromised. That is precisely what makes my move to Flutter worth listening to.
The real cost of “native everywhere”
Native gives you things you love: buttery-smooth performance, platform fidelity, full OS access. The cost shows up as the team grows:
- Two teams, two codebases, two bug lists. The same feature ships in iOS in 2 weeks, in Android in 4. Or vice versa. There is always a gap.
- “Works on iOS” ≠ “Works on Android” — every production incident is a two-platform investigation.
- Hiring: you look for two specialists instead of one. For a small team in Eastern Europe, this is literally the difference between shipping and not shipping.
- Knowledge silos — the iOS dev cannot help with an Android bug, and vice versa.
The industry tried to fix this several times. PhoneGap/Cordova (web in a wrapper). Xamarin (.NET everywhere, then bought and sunset). React Native (JS over a bridge to native). All had architectural ceilings.
What makes Flutter different (and why it matters now)
In 2017 Flutter showed up with a radical decision: it does not use native widgets, it paints its own pixels. Sounds minor. It is not. It means Flutter is not tied to any platform — it can render anything, anywhere there is a pixel canvas.
Three direct consequences:
- Own rendering engine (Skia, now Impeller) — no longer constrained by platform widgets, so it can run identically on iOS, Android, web, desktop, even on automotive embedded screens.
- Compiles to native ARM — not interpreted, not bridged. Performance is real.
- One language — Dart — for frontend, backend, games, CLIs, everything.
Together, these unlock use cases nobody expected when Flutter shipped as a mobile framework.
The “wait…” moment
Sometime in 2022 I caught myself thinking too small. If Flutter owns the rendering, and Dart compiles everywhere, why are we only building mobile apps with it?
So I decided to test the idea. Not with a toy project — with a real product that had to hold up under pressure.
Case study — Table Online, 100% Dart
Table Online is a classic real-time multiplayer backgammon game. Sounds simple, but requires: matchmaking, rating system, chat, server-side rule validation, admin panel for moderation, IAP. Team: TAGonSoft, small. Constraint: ship on iOS, Android and web, plus backend and admin.
The traditional approach would be: Unity for the game, Node.js/Go for the backend, React for the admin, Swift/Kotlin for the native variants. Four languages, four CI/CD pipelines, four kinds of developers.
We chose: Flutter + Flame for the game, Flutter Web for web players, Flutter Web for the admin panel, Serverpod for the backend. One language — Dart — everywhere.
┌──────────────────────────────────────────────────────┐
│ DART / FLUTTER │
├─────────────────┬─────────────────┬──────────────────┤
│ 🎮 Game │ 🌐 Web │ 📊 Admin │
│ Flutter + │ Flutter Web │ Flutter Web │
│ Flame Engine │ (players) │ (moderation) │
├─────────────────┴─────────────────┴──────────────────┤
│ 🔧 Serverpod (Dart) │
│ API · WebSockets · Auth · DB │
├──────────────────────────────────────────────────────┤
│ PostgreSQL · Redis │
└──────────────────────────────────────────────────────┘
Flame — game engine on top of Flutter
Flame is the 2D game engine built on Flutter. It is not a toy — it is production-ready. What makes it special: it runs on Flutter, so you can overlay regular Flutter widgets on the game. In-game chat? Regular Flutter widget. Pause menu? Regular Flutter. Hot reload works inside the game — Unity devs would pay for that.
class BackgammonBoard extends FlameGame
with HasDraggables, HasTappables {
@override
Future<void> onLoad() async {
final board = await Sprite.load('board.png');
add(SpriteComponent(sprite: board, size: size));
for (final piece in gameState.pieces) {
add(GamePiece(piece));
}
}
@override
Widget build(BuildContext context) {
return GameWidget(
game: this,
overlayBuilderMap: {
'chat': (ctx, game) => ChatOverlay(),
'menu': (ctx, game) => GameMenu(),
},
);
}
}
A Flame game is a Flutter widget. You can embed it anywhere, you can overlay anything on top. If you can build Flutter apps, you can build 2D games.
Serverpod — Dart backend with end-to-end type safety
Serverpod is what makes the stack truly powerful. You define the models once, and Serverpod generates the client. Change a field on the server — the client code stops compiling until you update it. The compiler becomes your integration test.
// Server endpoint (Dart)
class GameEndpoint extends Endpoint {
Future<GameState> makeMove(
Session session, int gameId, Move move,
) async {
final game = await Game.db.findById(session, gameId);
if (!game!.isValidMove(move))
throw GameException('Invalid move');
game.applyMove(move);
await Game.db.updateRow(session, game);
// Notify opponent via WebSocket
session.messages.postMessage(
'game_$gameId', GameMoveMessage(move: move));
return game.state;
}
}
// Client call (same Dart, same types)
final newState = await client.game.makeMove(gameId, myMove);
JSON serialization bugs disappear. “Client sends int, server expects string” bugs disappear. The team gains time it would otherwise burn debugging cross-stack.
What worked
- One developer can work across the full stack. No more “you’re a mobile person” or “you’re a backend person”. Everyone is a Dart person.
- Hot reload for game development — sub-second. In Unity you would wait 30+ seconds.
- ~40% shared code across the four products. Backgammon rule validation is written once and used identically on client and server.
- Type safety across the stack caught bugs at compile time that would otherwise have been production crashes.
- A small team shipped on three platforms in months, not years.
What was hard (the honest part)
I am not selling Flutter as a panacea. Some things were hard:
- Flutter Web performance — especially on first load. There are real trade-offs between Canvas and HTML renderers.
- The Flame ecosystem is smaller than Unity or Godot. Not a problem for 2D games, but for AAA 3D, use something else.
- Serverpod is young — fewer Stack Overflow answers. You need to be comfortable reading source code.
- Some pub.dev packages don’t support all platforms. Check before depending on them.
- Convincing other developers that Dart is a “real” backend language — more cultural battle than technical.
None were blockers. They are trade-offs. In engineering, you always have trade-offs.
What this means for your team
If you are a developer: learn Dart deeply, not just Flutter. Your skills extend across mobile, games, backend, CLIs.
If you are a tech lead: evaluate Flutter for your next greenfield project. Start with an internal tool or dashboard. Measure team velocity.
If you are a CTO or founder: think platform ROI, not just mobile ROI. One team, one language, faster time to market, lower total cost. In our experience, team-size reduction for the same output is between 30% and 50% — not a marketing number, but what we have observed in practice.
When Flutter is the answer (and when it isn’t)
Yes if you have a product that spans multiple platforms, a small-to-medium team that needs leverage, a 2D game / interactive experience, internal tools or dashboards, a startup that needs speed.
Not (yet) if you have an SEO-heavy content site, a 3D AAA game, very specialized native features, or a team deeply invested in another stack.
If you want to see the result directly, hop on table-online.ro and play a round. Everything you touch — from how the dice spin to how the score appears after a won match — was written by us in Dart, from pixel to SQL query.
Want to discuss a Flutter end-to-end project (mobile + web + backend)? Get in touch. And if you are looking for the PeakIT talk recording, follow the official PeakIT YouTube channel.