← Back to list

My Go-To Flutter Packages: The Essential Toolkit I Can’t Live Without (As a Flutter Dev)

Since diving into Flutter development in 2018, I’ve explored countless packages on pub.dev. Over the years, a select few have become…

Samfan · 2025-07-20 16:56 · 0 claps · 7.3 min read
#flutter #best-flutter-packages #flutter-package #flutter-app-development
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

My Go-To Flutter Packages: The Essential Toolkit I Can’t Live Without (As a Flutter Dev)

Since diving into Flutter development in 2018, I’ve explored countless packages on pub.dev. Over the years, a select few have become absolute mainstays in every single project I build. In this post, I’m excited to share these tried-and-true packages that have consistently boosted my productivity and code quality.

1. flutter_bloc

Link: pub.dev/packages/flutter_bloc

What it Does:

flutter_bloc (and its core bloc library) is a powerful and predictable state management solution for Flutter applications. It helps you separate business logic from your UI, making your code easier to test, maintain, and scale.

Why I Use It:

Since I began my Flutter journey in 2018, flutter_bloc has consistently been my go-to for state management, earning its spot as my absolute favorite. What I love most about it is how smoothly and cleanly it helps solve the complex problem of state management.

It provides a clear architectural pattern (events -> BLoC/Cubit -> states) that ensures a predictable flow of data and application state. This predictability is invaluable for debugging and understanding how changes propagate through the UI. It forces you to think about discrete events and states, leading to more robust and less error-prone applications. The separation of concerns it promotes is also fantastic for unit testing your business logic independently of the UI.

Alternatives:

While flutter_bloc is my preferred choice, there are other excellent state management solutions in the Flutter ecosystem:

  • **provider with ChangeNotifier:** A very popular and flexible option, provider can be combined with ChangeNotifier to manage and expose application state. It's often recommended for simpler applications or those needing more granular control.
  • **Riverpod:** A reactive caching and data-binding framework, Riverpod offers a more compile-safe and robust alternative to provider, addressing some of its potential pitfalls. I haven't extensively used Riverpod myself, primarily because flutter_bloc has consistently met all my project needs, and I haven't yet found a compelling reason to switch away from its predictable and robust architecture.

2. get_it

Link: pub.dev/packages/get_it

What it Does

get_it is a simple yet powerful service locator for Dart and Flutter. It allows you to register and retrieve instances of your classes (dependencies) throughout your application, decoupling their creation from their usage, which greatly simplifies dependency injection.

Why I Use It

For my larger Flutter applications, get_it has become an indispensable tool for dependency injection. While smaller apps might get by with passing dependencies manually, once your project grows, managing objects and their lifecycle can become a tangled mess.

get_it provides a lightweight and straightforward way to access singletons and other registered instances from anywhere in your widget tree or business logic, without relying on BuildContext or complex inheritance. This makes my code significantly cleaner, more modular, and easier to test. I particularly appreciate its simplicity; it avoids the boilerplate often associated with more complex DI frameworks, allowing me to focus on the core logic rather than wiring up dependencies. It's a pragmatic choice that delivers great benefits without unnecessary overhead.

Alternatives

While get_it serves my needs perfectly for dependency injection, here are a couple of other approaches or packages:

  • **Provider (for simple cases):** For very simple dependency provision (e.g., exposing a single service to a subtree), Provider can sometimes serve a similar role, especially when combined with its create method. However, get_it is a dedicated service locator, offering more global access and explicit registration.
  • Manual Dependency Injection: In very small applications, you might pass dependencies down the widget tree manually through constructors. This works for tiny apps but quickly becomes unwieldy and hard to manage in larger projects, which is exactly where get_it shines.

Okay, here’s the section for the logger package, formatted in plain text for your blog post:

3. logger

Link: pub.dev/packages/logger

What it Does

logger is a pretty, easy-to-use, and extensible logger for Flutter and Dart. It offers various logging levels (verbose, debug, info, warning, error, WTF) and provides highly readable output, including log levels, file names, line numbers, and even a stack trace.

Why I Use It

Debugging can be a time-consuming part of development, and standard print() statements often fall short. That's where logger steps in as an essential tool in my toolkit. I use it in every project because it significantly enhances the visibility into my application's behavior.

The beautifully formatted output is incredibly helpful; I can quickly distinguish between different types of messages (info, warnings, errors) thanks to its color-coding and structured display. It automatically includes the file and line number where the log originated, which is a massive time-saver for pinpointing issues. For critical errors, the ability to easily output a full stack trace directly in the console is invaluable. It helps me debug more efficiently and keep my console output clean and organized compared to scattered print() statements.

Alternatives

While logger is my preferred choice for detailed and formatted logging, here are common alternatives:

  • **print() function:** The built-in Dart print() function is the simplest way to output messages to the console. It's fine for very quick, temporary checks, but lacks formatting, levels, and the ability to easily disable logs in production.
  • **dart:developer's log() function:** This provides slightly more features than print(), allowing for named sections and object logging, but still doesn't match the rich, structured output of logger.

4. go_router

Link: pub.dev/packages/go_router

What it Does

go_router is a declarative routing package for Flutter, designed to simplify navigation for complex applications. It handles deep linking, nested navigation, authenticated routes, and provides a robust way to manage the navigation stack, especially in web and desktop environments where URL-based routing is crucial.

Why I Use It

For my larger applications that demand sophisticated navigation patterns, go_router has become my preferred solution. It's important to note that for smaller apps, I often stick with Flutter's built-in Navigator 1.0 (using Navigator.push and Navigator.pop) as it's perfectly adequate and simpler to set up. However, go_router truly shines when you're dealing with complex routing logic, such as nested stateful routes, shell routes, or deep linking scenarios where the Navigator 1.0 approach quickly becomes unwieldy.

It provides a declarative and intuitive API for defining your entire routing tree, making it easy to visualize and manage how users move through your app. A significant factor in my adoption of go_router was its direct support by the Flutter team. This brings a level of confidence in its long-term maintenance, stability, and alignment with future Flutter developments, which is paramount for critical application infrastructure like routing. It simplifies handling navigation state and makes URL-driven navigation seamless.

Alternatives

Before settling on go_router, I explored other routing packages, most notably:

  • **auto_route:** This is another excellent and popular package that uses code generation to create routes. I used auto_route for a period and found it highly capable, especially for quickly generating a large number of routes. However, I eventually switched to go_router primarily due to the Flutter team's direct backing, which felt like a more stable long-term bet for my enterprise-level applications.
  • Built-in Navigator (v2 - Router and RouterDelegate): Flutter's native Navigator 2.0 (using Router and RouterDelegate) offers full control over navigation. While powerful, Navigator 2.0 can be quite verbose and complex to implement from scratch for intricate use cases. go_router essentially abstracts much of this complexity, providing a much friendlier API over Navigator 2.0, while still leveraging its underlying power.

5. dio

Link: pub.dev/packages/dio

What it Does

dio is a powerful HTTP client for Dart and Flutter. It provides a robust set of features, including interceptors, global configuration options, request cancellation, file uploading/downloading, and robust error handling, making it suitable for complex networking requirements.

Why I Use It

When it comes to handling network requests in my Flutter applications, dio is my absolute go-to. I initially used the http package, which is perfectly good for basic requests, but I quickly found its limitations when dealing with more complex scenarios. dio, on the other hand, is incredibly feature-rich and has significantly streamlined my networking layer.

My favorite aspects of dio revolve around its support for interceptors. This feature is a game-changer! I can easily set up global logic for tasks like adding authentication tokens to every outgoing request, logging requests and responses (especially with the helpful pretty_dio_logger package that I also use in every app), or even retrying failed requests.

The way dio handles error management is particularly robust. For applications with authentication, its ability to gracefully manage token refresh during error handling is a huge win – it saves so much boilerplate code and ensures a smooth user experience. Furthermore, common features like caching can also be implemented very smoothly using interceptors, centralizing my networking logic effectively. The flexibility to set options and headers per instance also helps keep my code clean and adaptable.

Alternatives

Before dio, or for simpler use cases, you might consider:

  • **http:** Flutter's official HTTP package is lightweight and perfectly suitable for basic GET/POST requests without complex requirements. It's often recommended for beginners or apps with minimal networking needs. However, it lacks built-in interceptors and advanced features found in dio.

6. equatable

Link: pub.dev/packages/equatable

What it Does & Why I Use It

equatable is a simple yet incredibly powerful package that I use in almost every Flutter project. Its main job is to help you easily compare Dart objects based on their values, not just their memory addresses.

Why is this important? By default, Dart objects are only equal if they’re the exact same instance. But often, you want to know if two objects represent the same data. For example, when using state management packages like flutter_bloc, equatable ensures that if your new state has the same data as the previous one, it's correctly identified as "equal." This prevents unnecessary UI rebuilds and makes your state logic predictable. It does this by simplifying the overriding of the == operator and hashCode getter, saving tons of boilerplate code and potential bugs.

Conclusion

We’ve covered a selection of Flutter packages that have truly become the backbone of my development workflow: from robust state management with flutter_bloc and efficient dependency injection with get_it, to reliable networking with dio, crystal clear debugging with logger, and seamless object comparison with equatable. For larger projects, go_router proves indispensable for handling complex navigation.

These tools, forged by the incredible Flutter community, empower us to build more maintainable, scalable, and delightful applications with greater ease and confidence. Adopting a well curated set of packages like these can significantly boost your productivity and the overall quality of your codebase.

As you discover and use your favorite packages, remember that they are built and maintained by dedicated developers, often on a voluntary basis. Please consider supporting these developers and the open source projects that keep our Flutter ecosystem vibrant and alive, whether through contributions, sponsorships, or simply by giving them a star on GitHub.

I’m excited to dive deeper into some of these topics and share more of my experiences in future posts, including practical examples and advanced usage tips.

For now, I’d love to hear from you! What are your absolute favorite Flutter packages that you can’t imagine building an app without? Share your go to tools and why you love them in the comments below. Let’s learn from each other and continue building amazing things with Flutter!


메타데이터
post_id
39a7b52acdce
slug
my-go-to-flutter-packages-the-essential-toolkit-i-cant-live-without-as-a-flutter-dev-39a7b52acdce
url
https://medium.com/@samfan/my-go-to-flutter-packages-the-essential-toolkit-i-cant-live-without-as-a-flutter-dev-39a7b52acdce
canonical_url
https://medium.com/@samfan/my-go-to-flutter-packages-the-essential-toolkit-i-cant-live-without-as-a-flutter-dev-39a7b52acdce
author_url
https://medium.com/@samfan
status
ok
fetched_at
2026-07-21 23:19:27