---
title: "Flutter performance: when to use Rust and FFI, when profiling is enough"
description: "Flutter is rarely the problem. Two FlutterCon 2026 talks show when Rust via FFI gives you 100x and when a single ticker cooks your GPU. Plus how to find the bottleneck."
canonical_url: "https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling"
last_updated: "2026-10-20T00:00:00.000Z"
locale: en
meta:
  "og:description": "Flutter is rarely the problem. Two FlutterCon 2026 talks show when Rust via FFI gives you 100x and when a single ticker cooks your GPU. Plus how to find the bottleneck."
  "og:image": "https://robocitrus.com/images/blog/flutter-performance-wann-rust-ffi-und-profiling.webp"
  "og:title": "Flutter performance: when to use Rust and FFI, when profiling is enough"
---

> Index of every page on this site: [llms.txt](https://robocitrus.com/llms.txt)

![Is Flutter fast enough? When you need Rust and how to find out (AI-generated cover image)](https://robocitrus.com/cdn-cgi/image/w=2048,q=75/images/blog/flutter-performance-wann-rust-ffi-und-profiling.webp)

# **Is Flutter fast enough? When you need Rust and how to find out**

[![Maximilian Flechtner](https://robocitrus.com/cdn-cgi/image/q=75/images/about-me-maximilian-image.webp)**Maximilian Flechtner**](https://robocitrus.com/en/about)

Published:October 20, 2026

1 min read

[**Flutter**](https://robocitrus.com/en/blog/tags/flutter) [**Performance**](https://robocitrus.com/en/blog/tags/performance) [**Rust**](https://robocitrus.com/en/blog/tags/rust) [**FFI**](https://robocitrus.com/en/blog/tags/ffi) [**Profiling**](https://robocitrus.com/en/blog/tags/profiling) [**App-Development**](https://robocitrus.com/en/blog/tags/app-development)

## The wrong question

"Is Flutter fast enough?" I hear this all the time. Most of the time it's the wrong question.

At FlutterCon 2026 I sat through two talks that look unrelated at first. One was about bringing Rust into Flutter via FFI to process images extremely fast. The other was about why an innocent-looking screen drains your GPU and battery.

Put together, they give me one clear line: measure first, then decide. Sometimes the answer is Rust. More often it's that you have a ticker running somewhere that never goes to sleep.

## Talk 1: when Dart really is too slow

The speaker had an automated pipeline that generates images. Out came Full HD or 2K images, and they had to be upscaled to 4K. With the Dart `**image**` package, that single step took around 10 seconds on a MacBook M4. At thousands of images a day, that hurts.

He had two options. Improve the package himself, or hook in native code. He went with Rust and built the package **[**Pixer**](https://pub.dev/packages/pixer)**.

The numbers from the talk:

- Upscaling Full HD to 4K: about 6 seconds with `**image**`, about 70 milliseconds with Pixer. Roughly 100x.
- Upscaling plus JPEG encoding: around 1000x, according to the speaker.

Where does that come from? Rust compiles via LLVM into very efficient machine code. On top of that: SIMD instructions, multithreading for resizing, and well-optimized algorithms from the Rust ecosystem. He also said the `**image**` package isn't written in a very compiler-friendly way in places.

### Why Rust and not C++ or Swift/Kotlin?

His reasoning made sense to me:

- Rust has a real package manager in Cargo and gives you memory safety. C and C++ have neither.
- Native Swift and Kotlin versions would mean writing the library multiple times. With Rust there's one codebase for every platform.
- He deliberately skipped Flutter Rust Bridge to keep control. His advice for beginners: learn the manual route first ( `**cbindgen**` generates C headers from Rust, `**ffigen**` generates Dart bindings from those), then move to the bridge if you like.

### Where FFI bites

Three things stood out.

**Few crossings.** Every call across the Dart/Rust boundary costs something. Pixer uses a builder pattern: you chain operations like resize or blur, but nothing happens yet. Only when you save does everything go to Rust in one single call. The C surface has only about ten functions.

**Memory.** The image lives on the Rust heap, Dart only holds a small pointer. The garbage collector sees just that tiny object and never frees the 12 to 100 MB of image data. The fix: `**Finalizable**` plus a `**NativeFinalizer**` that calls free on the Rust side. Add the `**externalSize**` parameter so the GC knows the real footprint and reacts to it.

**Distribution.** Building and bundling native libraries per platform is painful. Pixer uses build hooks and downloads prebuilt binaries from GitHub Releases, with a hash check. Nobody needs a Rust toolchain. The binaries are about 2 MB on ARM and 5 MB on x86. If you only need PNG, you can compile just those codecs through Cargo features.

### When FFI makes sense, according to the talk

When Dart has a known bottleneck and an optimized native solution exists. Typical cases: crypto, image, audio, video, large data on the device. Not great: very frequent but trivial calls, where crossing the boundary costs more than it saves.

And the most important sentence: don't use Rust for Rust's sake. Benchmark and profile your Dart code first, and go native only for a confirmed problem.

## Talk 2: when Dart isn't slow, the GPU is sweating

The second talk flipped the question. The example was a ClickUp-style screen: a dialog with a blurred background and a `**CupertinoTextField**`. Looks simple. Isn't.

### What blur really costs

Blur needs information from neighboring pixels. But the GPU renders in tiles. So it has to finish the background, write it to memory, read it back, blur it, and then put the UI on top. A frame on a current iPhone is around 24 MB according to the talk, and going out and back doubles the memory traffic. One render pass turns into several.

Computed once, that's no drama. In Xcode's energy profile the screen even looked relaxed while idle, because no new frames were being requested.

### The real culprit: a ticker

As soon as the text field got focus, GPU load spiked. The reason is the cursor, which fades in and out. It runs on an `**AnimationController**`, and an active ticker requests frames at the full display rate, up to 120 per second on some devices. The UI might change eight times a second, but the blur gets computed 120 times.

An earlier Flutter PR cut the cursor updates to 8 Hz. That helps CPU and rebuilds, but the ticker still requests full-rate frames. The result: heat, battery drain, throttling, and in the worst case dropped frames.

The line I took away: a demo running at 120 FPS isn't automatically sustainable. Fast and cheap are two different things.

### What you can do about it

- **Control your tickers.** Not every animation needs full frame rate. The FixTicker package offers a ticker-like API that schedules frames through timers.
- **Turn off the cursor fade.** On `**CupertinoTextField**` you can switch the cursor to blinking instead of fading, if you can live with the look.
- **Stop tickers behind sheets.** Flutter mutes tickers behind fully opaque routes, but not behind non-opaque ones like sheets. That's on you.
- **Use blur carefully.** One backdrop blur can be reused for several elements. If you animate blur, it has to end at exactly 0.0. A tiny leftover value still costs an extra pass. And cost doesn't rise linearly with sigma but in steps, because higher values allow more downsampling.
- **No Opacity over complex trees.** It forces offscreen rendering. Paint with a transparent color or pass opacity straight to images instead.
- **Swap out ShaderMask.** For fades at list edges, a gradient overlay often does the job when the background is known.
- **Keep layers tight.** Smaller areas mean smaller textures.

### Profiling

The tools: [**DevTools**](https://docs.flutter.dev/tools/devtools) for CPU and UI, `**RepaintBoundary**` to trace paints, and on iOS Metal System Trace and Metal Frame Capture in Xcode. There you see the individual passes: background, downsample, vertical blur, horizontal blur, compositing. The workflow in the talk: profile build, enable GPU frame capture in the scheme, capture a frame, look at the dependencies.

The speakers also showed an experimental package that estimates frame cost in widget tests, plus three skills for AI agents: what makes a frame expensive, what keeps drawing, and how to profile. An open Flutter PR would let tickers request frames only when something actually changes. According to the talk it has been merged twice and reverted twice.

## My case: the seat-plan algorithm in DragonBoat Hub

For me Rust isn't a theory topic. I use it in [**DragonBoat Hub**](https://robocitrus.com/en/projects/dragonboat-hub), specifically for the algorithm that calculates the seating in a dragon boat. It assigns paddlers to seats based on weight, experience and balance, and it runs many attempts until the best lineup is found.

The history of that algorithm is an honest example of "measure first, rebuild second":

1. **JavaScript:** The original is DragonTrim by Christian, written in JS.
2. **Dart port:** In spring I ported it to Dart so it could run directly inside the [**Serverpod**](https://serverpod.dev) server.
3. **JS as a sidecar:** At the end of April I threw the Dart port out again and ran the JS original as a sidecar process.
4. **Rust sidecar:** Today a Rust port runs as the sidecar. It is checked against the JS original with a differential test and returns byte-identical answers for the same request.

I re-measured this on 17 October 2026 on an Apple M4 Pro. The input was a realistic 20-seat boat with 20 paddlers, propulsion balancing on and 100 attempts, like in production:

| **Implementation** | **Median** |
| --- | --- |
| Dart port (deep variant) | 1031.6 ms |
| Dart port (base variant) | 278.8 ms |
| JS original, Node | 103.7 ms |
| JS, Bun | 61.9 ms |
| Rust, single thread | 7.7 ms |
| Rust, all cores | 1.1 ms |

Over local HTTP it's 1.7 ms for the Rust sidecar against 97.8 ms for the Node sidecar.

Two notes so the picture doesn't get skewed. First: I used to say the Dart port took "several seconds". Measured on my laptop it's about one second. On a small server it may take longer, but I haven't measured that. Second: one second isn't dramatic on its own. But 1 millisecond instead of 100 or 1000 changes what you can do with it, and the load per request on the server shrinks accordingly.

That fits what the Pixer talk showed: Rust pays off for real compute work with a clear bottleneck. It also fits my order below. I didn't jump straight to Rust. I went through Dart and JS first and measured each step. The real point for me: the differential test against the JS original is the safety net, not my trust in the new code. As long as both return the same answers, I can swap the implementation.

Rust doesn't only run on the server in my setup, though. The scoring of how good a boat's lineup is lives in its own Rust crate, and I link exactly that crate into the Flutter app via [**flutter\_rust\_bridge**](https://github.com/fzyzcjy/flutter_rust_bridge). The reason isn't speed, it's consistency. The app used to have a Dart re-implementation of the scoring, and the two sides had drifted apart: some penalties were set to zero in the app while they cost 10000 on the server. The number a coach saw in the app wasn't the number the optimizer was minimising. Today app and server calculate with the same code, and a parity test keeps both bit-identical across 1206 optimizer runs.

The search itself stays on the server. The app only gets the scoring half, because libraries for parallel search and HTTP have no business on a phone. That's why the crate is split in two, and the compiler makes sure it doesn't get mixed up again. How Serverpod fits in is covered in [**my comparison with Supabase and Firebase**](https://robocitrus.com/en/blog/serverpod-vs-supabase-vs-firebase).

## My take: order beats technique

I build apps with [**Flutter**](https://robocitrus.com/en/blog/warum-ich-flutter-liebe), and for most of my projects performance was never the source of trouble. That's my experience, not a quote from the talks. The order I take away from all this:

1. **Does it run smoothly on a real, older device?** If yes, stop.
2. **If not: profile build, DevTools.** Is it UI thread work or the raster side?
3. **Raster side?** Blur, opacity, ShaderMask, a forgotten ticker. For normal apps, that's where most of the wins are.
4. **UI thread doing real heavy lifting?** Isolates first, then a better package, and only then FFI.
5. **Rust only for a confirmed bottleneck** like image, audio or video processing, where a mature native ecosystem exists.

What I find interesting is that AI agents lower the barrier for step 5. The speaker says himself that you can delegate this kind of work with simple instructions today. That matches what I wrote in [**AI in app development**](https://robocitrus.com/en/blog/ki-in-der-app-entwicklung). But easier to build doesn't mean easier to maintain. Every native dependency is another build you have to watch on every platform.

One more thing: the [**native vs. cross-platform**](https://robocitrus.com/en/blog/native-app-vs-cross-platform) debate often treats performance as the deciding factor. Both talks show that with Flutter you can go native when you need to. That takes the edge off the argument. You can find a direct comparison of two frameworks in [**Flutter vs React Native 2026**](https://robocitrus.com/en/blog/flutter-vs-react-native-2026).

## Conclusion

Flutter is fast enough in the vast majority of cases. When it isn't, the cause is often not the language but frames: too many of them, too many passes.

Rust via FFI is a strong tool for real compute load, up to 100x to 1000x for images in the talk. But it's the last step, not the first. Measure first, then build.

---

## Frequently asked questions (FAQ)

Mostly yes. The talks show that bottlenecks almost always sit in specific places: heavy computation or expensive render effects. Both can be fixed in a targeted way without switching frameworks.

When you have a measured bottleneck in Dart and a mature native solution exists, for example in image, audio or video processing, or cryptography. With very many small calls, the crossing itself can cost more than you gain.

The speaker recommends beginners learn the manual route with `**cbindgen**` and `**ffigen**` first. Then you understand what the bridge does for you behind the scenes and can use it deliberately.

A common reason is an active ticker or a constant animation requesting frames at full display rate. Combined with blur or offscreen opacity, every one of those frames gets expensive. Profiling with Xcode and DevTools shows what is actually running.

Always measure in profile mode on a real device. DevTools for CPU and UI, and on iOS Metal System Trace and Frame Capture for the GPU side. Optimize only once you know the bottleneck.

---

*This article was inspired by two talks at FlutterCon 2026: one on Rust and FFI for image processing with Pixer, and one on the GPU cost of blur and tickers in Flutter.*

[**Flutter beyond the phone: multi-window, iPad and adaptive layouts** The scene lifecycle becomes mandatory and many iPad apps are just scaled-up iPhone apps. What multi-window, a headless engine and adaptive layouts mean for your Flutter app.](https://robocitrus.com/en/blog/flutter-multi-window-adaptive-ui-tablets-foldables) [**Where is Flutter heading? The 2026 roadmap and how to safely rebuild a huge app** Where is Flutter going? Design system decoupling, analyzer performance, AI agents. Plus a real-world case: how a team safely refactored a banking app with 100 developers.](https://robocitrus.com/en/blog/flutter-roadmap-2026-und-grosse-refactorings)

## **Let's Connect! 🚀**

### **Ready for your next project? **<br>** Let's get started!**

![Maximilian Flechtner - Gründer](https://robocitrus.com/cdn-cgi/image/w=3840,f=png,q=75/images/about-me-maximilian-image.webp)

#### **Maximilian Flechtner **

[flechtner@robocitrus.com](mailto:flechtner@robocitrus.com) [ +49 0176 41766223](tel:+4917641766223)

### **Let's get started**

Tell me about your vision – just drop me an email or use the contact form. Let's plan your digital success together! 💪

[Send me an email](mailto:flechtner@robocitrus.com) [Contact Form](https://robocitrus.com/en/kontakt)

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://robocitrus.com/en#website","@type":"WebSite","description":"App Entwickler & Full-Stack Experte aus Deutschland. Ich baue skalierbare Apps, Backends und komplette Startup-Systeme mit Flutter, Go und Kubernetes.","inLanguage":"en-US","name":"Maximilian Flechtner - App Entwickler","url":"https://robocitrus.com/en","publisher":{"@id":"https://robocitrus.com/#/schema/organization/1"},"translationOfWork":{"@id":"https://robocitrus.com/#website"}},{"@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling#webpage","@type":"WebPage","dateModified":"2026-10-20T00:00:00.000Z","datePublished":"2026-10-20","description":"Flutter is rarely the problem. Two FlutterCon 2026 talks show when Rust via FFI gives you 100x and when a single ticker cooks your GPU. Plus how to find the bottleneck.","name":"Flutter performance: when to use Rust and FFI, when profiling is enough","url":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling","breadcrumb":{"@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling#breadcrumb"},"isPartOf":{"@id":"https://robocitrus.com/en#website"},"potentialAction":[{"@type":"ReadAction","target":["https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling"]}],"primaryImageOfPage":{"@id":"https://robocitrus.com/#logo"}},{"@id":"https://robocitrus.com/#identity","@type":"Organization","alternateName":"Robocitrus","description":"App Entwickler & Full-Stack Experte aus Deutschland. Spezialisiert auf skalierbare Apps, Backend-Systeme und komplette Startup-Lösungen mit Flutter, GoLang und Kubernetes. Von der Idee bis zum Launch - alles aus einer Hand.","email":"flechtner@robocitrus.com","name":"Maximilian Flechtner - App Entwicklung","telephone":"0176 41766223","url":"https://robocitrus.com","address":{"@type":"PostalAddress","streetAddress":"Leppiner Dorfstraße 60","addressLocality":"Arendsee","addressRegion":"Sachsen-Anhalt","postalCode":"39619","addressCountry":"DE"},"contactPoint":{"@type":"ContactPoint","telephone":"0176 41766223","email":"flechtner@robocitrus.com"},"logo":{"@id":"https://robocitrus.com/#logo"}},{"@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling#article","dateModified":"2026-10-20T00:00:00.000Z","datePublished":"2026-10-20","description":"Flutter is rarely the problem. Two FlutterCon 2026 talks show when Rust via FFI gives you 100x and when a single ticker cooks your GPU. Plus how to find the bottleneck.","headline":"Is Flutter fast enough? When you need Rust and how to find out","inLanguage":"en-US","thumbnailUrl":"https://robocitrus.com/images/blog/flutter-performance-wann-rust-ffi-und-profiling.webp","wordCount":200,"@type":["Article","BlogPosting"],"author":{"@id":"https://robocitrus.com/#/schema/person/1"},"image":{"@id":"https://robocitrus.com/#/schema/image/1"},"isPartOf":{"@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling#webpage"},"keywords":["Flutter","Performance","Rust","FFI","Profiling","App-Development"],"mainEntityOfPage":{"@type":"WebPage","@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling"},"publisher":{"@id":"https://robocitrus.com/#/schema/organization/1"}},{"@id":"https://robocitrus.com/en/blog/flutter-performance-wann-rust-ffi-und-profiling#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Blog","item":"https://robocitrus.com/blog","position":1},{"@type":"ListItem","name":"Is Flutter fast enough? When you need Rust and how to find out","position":2}]},{"@id":"https://robocitrus.com/#/schema/person/1","@type":"Person","name":"Maximilian Flechtner","url":"https://robocitrus.com/about","image":{"@id":"https://robocitrus.com/#/schema/image/2"}},{"@id":"https://robocitrus.com/#/schema/organization/1","@type":"Organization","name":"Maximilian Flechtner - App Entwicklung","url":"https://robocitrus.com/","logo":{"@type":"ImageObject","url":"https://robocitrus.com/images/large-logo.webp"}},{"@id":"https://robocitrus.com/#logo","@type":"ImageObject","caption":"Maximilian Flechtner - App Entwicklung","contentUrl":"https://robocitrus.com/images/large-logo.webp","inLanguage":"en-US","url":"https://robocitrus.com/images/large-logo.webp"},{"@id":"https://robocitrus.com/#/schema/image/1","@type":"ImageObject","contentUrl":"https://robocitrus.com/images/blog/flutter-performance-wann-rust-ffi-und-profiling.webp","inLanguage":"en-US","url":"https://robocitrus.com/images/blog/flutter-performance-wann-rust-ffi-und-profiling.webp"},{"@id":"https://robocitrus.com/#/schema/image/2","@type":"ImageObject","contentUrl":"https://robocitrus.com/images/about-me-maximilian-image.webp","inLanguage":"en-US","url":"https://robocitrus.com/images/about-me-maximilian-image.webp"}]}
```

## Sitemap

See the full [sitemap](https://robocitrus.com/sitemap.md) for all pages.
