Flutter: A Dream or a Developer’s Nightmare?

Setting the Stage

In this article, I will discuss the Flutter framework and its ecosystem. Over a period of 7–8 weeks, my team and I had the opportunity to experiment with Flutter while developing our Community-Driven History App. Our main goal was to create an application that could be easily ported to multiple platforms, with a particular focus on Android and iOS, as these are the most commonly used devices among our target audience.

Flutter is an open-source framework for building beautiful, natively compiled, multi-platform applications from a single codebase. At first, we thought this would be a breeze—but we were quickly knocked off our high horse and plunged headfirst into our own little personal hell: Flutter.

The Numbers Behind Flutter’s Success

In the latest Stack Overflow Developer Survey 2024, Flutter clearly outpaces React Native in popularity. Beyond these two, no other multi-platform frameworks really stand out. Looking at their GitHub repositories, Flutter boasts 170,000 stars, a solid 50,000 more than React Native. Safe to say, Flutter is here to stay.

An honorable mention goes to Xamarin, Microsoft’s attempt to compete in this space. Any developer doing extensive research will stumble upon it, only to find out that support ended last year. Microsoft does offer a migration path to .NET, which, arguably, is more popular than both Flutter and React Native combined. However, their primary focus doesn’t seem to be mobile development.

Diving into Flutter’s documentation, it quickly became clear why it’s so popular. Once you get the hang of Dart’s syntax and the powerful Widget system, development feels like a breeze. I’ve never picked up a framework’s core concepts this quickly—and it felt amazing. But could I see the curve rising, only to crash soon after? I didn’t.

Flutter’s Package Ecosystem: A Work in Progress

Take a moment to visit pub.dev and browse the most popular packages. With over 52,000 available, it’s clear how vast the Flutter ecosystem is. Whatever you can think of, there’s probably a package for it. However, this feels more like a curse than a blessing. The vast majority of these packages are either one-time releases or outdated updates, with many no longer working as intended. Flutter’s ecosystem seems stuck in a vicious cycle.

And this is where Flutter’s biggest problem lies. I won’t dive too deep into our specific use cases—those will be covered in separate blog posts—but let’s just say we’ve seen a side of Flutter we weren’t supposed to see. It genuinely makes us wonder: how did it get to this point?

While experimenting with yet another update built on top of the outdated ar_flutter_plugin, we quickly ran into a major roadblock: core functionality was simply missing. The package hadn’t implemented all platform-specific features, such as Android’s ARCore and iOS’s ARKit.

It felt like a real defeat. It was as if the community had turned its back on exciting technologies, focusing instead on churning out yet another HTTP request API. This may sound harsh, but compared to React Native’s Expo, Flutter lacks a clear structure and overview of what’s truly possible. And that, in our opinion, should be its most important unique selling point.

ALSO READ: Augmented Reality: A Sad Reality?

Google, Where Art Thou? A Call for More Support

Notice the elephant in the room? It’s time to address it: Google… what’s going on? They claim to be Flutter’s biggest supporter, yet many of their own APIs aren’t natively available in the framework. Instead, developers are left relying on third-party packages—many of which are incomplete, outdated, or simply inefficient. Far too often, these packages fall back on basic HTTP Web Services, when a direct API implementation would be far more performant.

Yes, Flutter is community-driven, but let’s be real: you can’t expect independent developers to keep up with the workload of a company like Google. They have the resources to make their APIs seamlessly accessible within Flutter—so why don’t they?

This ecosystem is backed by some of the biggest players in tech, yet it often feels like they’re actively discouraging newcomers from embracing the framework. Writing duplicate implementations for APIs that already exist, only to have them barely function, is beyond frustrating. And the worst part? Google isn’t even trying to hide it anymore—many of their own API guides don’t even offer a real solution.

This isn’t a sustainable way to stay relevant. Every week, it feels like another dozen packages become obsolete for no reason, forcing us to choose between two undesirable options: bad code practices and unstable code, or custom implementations. Let me tell you, in just six weeks, there simply wasn’t enough time for the second option.

➡ ALSO READ: API Restrictions vs. Restrictive APIs: What’s the Real Issue?

Author's note

While conducting further research, I came across this section of the Flutter documentation, which adds a layer of nuance to the feedback we’ve shared about Google. If you’d like to dive deeper into this topic, I recommend checking out API Restrictions vs. Restrictive APIs.

Clear on Security, Chief? Not Quite.

Almost all frameworks offer a built-in way to securely store API keys. These keys are valuable and, if in the wrong hands, can quickly cost you a fortune. But only after spending significant time within the Flutter ecosystem do you realize that securing API keys isn’t as straightforward as it seems—often, you’re far from the places you’d typically look (thankfully, a fellow developer stepped in to help, thank you!).

Even then, you’ll probably need to jump through some impossible hoops, only to end up with the API key sitting somewhere in your native platform code.

I’ll stop here, as security is a hot topic that deserves its own in-depth discussion, but I think the message is clear.

➡ ALSO READ: Firebase, A Thank You Letter

Wrapping Up: The flutter ecosystem dilemma

Ultimately, our biggest issue with the Flutter ecosystem is this:

That being said, we haven’t touched on everything. There are good aspects too—state management and BLoC deserve their time in the spotlight.

And if you feel like we’re missing one last core piece of the Flutter puzzle, you’re absolutely right. Read on to find out why we love Dart.

Dart? Bull's Eye!

We’ve taken a deep dive into what frustrates us about Flutter, with the package ecosystem being a major culprit. But to be fair, it’s just as important to highlight what Flutter gets right. Because when it does, it just works.

In short, Dart feels like it was made for Flutter—much like Kotlin and Jetpack Compose were made for Android development. And that makes all the difference. For us, third-year students who have navigated through a variety of programming languages, Dart was easy to pick up after just a quick glance at the documentation. It’s a type-safe language with excellent type inference, which made it feel familiar—similar to TypeScript in that regard. The clean, no-nonsense syntax resembles languages like Kotlin and TypeScript, yet Dart retains the power and structure of languages like Java and C#.

Example: Null Safety

Unlike JavaScript, Dart supports null safety. In Dart, all types default to non-nullable. This benefits Dart developers because Dart catches null reference exceptions when writing code, rather than at runtime.

				
					// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo(); // Foo() invokes a constructor
				
			

Null-Aware Operators

Dart supports several operators to deal with nullability. As in JavaScript, Dart supports the null assignment operator (??=), null-coalescing operator (??), and optional chaining operator (?.). These operators work the same as JavaScript.

! Operator

In cases where a nullable variable or expression might be non-null, you can tell the compiler to repress any compile time errors using the (!) operator. Place this operator after the expression.

				
					int? a = 5;

int b = a; // Not allowed.
int b = a!; // Allowed.
				
			

Example: Futures (Dart) & Promises (JS)

Future is Dart’s version of a JavaScript Promise. Both are the result of an asynchronous operation that resolves at a later point.

Javascript

				
					const httpResponseBody = func();

httpResponseBody.then(value => {
  console.log(
    `Promise resolved to a value: ${value}`
  );
});
				
			

Dart

				
					Future httpResponseBody = func();

httpResponseBody.then((String value) {
  print('Future resolved to a value: $value');
});
				
			

The example above highlights just a few reasons why we love Dart. Even with just a few lines of code, Dart stands out when compared to JavaScript. The types are explicit, and there’s no clutter—no unnecessary symbols like the fat arrow operator. If you value clean, clear code wrapped in a neat package, Dart is definitely the way to go.

Dart: Advanced

The code snippet below showcases another powerful feature in Dart, often considered to be a sibling of Future: Stream. This allows for more advanced asynchronous operations. You can try it out yourself on DartPad.

				
					Stream countStream() async* {
  for (var i = 0; i < 5; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

void main() {
  countStream().listen((data) {
    print('Received: $data');
  });
}
				
			

Dart: The Secret Sauce Behind Flutter’s Success

In conclusion, Dart’s seamless integration with Flutter is one of its strongest features, making it feel tailor-made for the framework—much like Kotlin with Jetpack Compose for Android development. With its clean syntax, type safety, and robust performance, Dart provides an intuitive experience that allows developers to focus on building rather than dealing with complex language nuances.

From null safety and advanced null-aware operators to Futures and Streams, Dart equips developers with the tools they need to handle asynchronous tasks with ease. If you value clarity, type safety, and streamlined syntax, Dart is a language that delivers a smooth, efficient coding experience.

There’s much more to Dart than we’ve covered here, but this provides a strong foundation to appreciate its power and versatility in Flutter development.

Flutter: The Final Verdict

In conclusion, our journey with Flutter has been a mixed bag of highs and lows. While Flutter offers great potential, particularly for traditional apps, its ecosystem still faces significant challenges—especially when it comes to package stability and integration with Google’s own APIs. However, Dart, the language behind Flutter, stands out as a clear winner, providing a clean, intuitive, and efficient way to develop applications. For those willing to work through the ecosystem’s growing pains, Flutter combined with Dart can be a powerful tool for cross-platform development. But as with any technology, it’s essential to weigh both its strengths and limitations before diving in.

We’d love to hear your thoughts and experiences with Flutter and Dart. Feel free to leave your comments below—we’re always open to discussion!

Sources

Leave a Reply

Your email address will not be published. Required fields are marked *

Table of Contents

SYNNOVATION