https://medium.com/reversebits/the-ultimate-guide-to-flutters-most-useful-packages-e39a5334451f
While working on different Flutter projects, I came across some libraries that really made my life easier. Instead of building everything from scratch, I found that using the right packages can save a lot of time and help avoid common issues.
In this blog, I’m listing down the libraries I use the most — for things like state management, API handling, navigation, animations, and UI components.
These are not just random packages, but ones I’ve actually used in real projects. I’ll explain why I picked them, how they helped, and maybe share a few small code examples.
If you’re also working with Flutter and looking for tools that can speed up your development or improve your code quality, you might find something useful here. Hope it helps!
1. Melos (monorepo management tool)
Melos is a very useful tool for managing flutter projects that follow a monorepo structure. when a project has multiple dart or flutter packages like separate feature modules, shared components, or utilities, melos helps keep everything organized.
It allows developers to run commands across all packages at once, saving time and avoiding repetitive work. with just one command like melos bootstrap, it installs dependencies and links local packages automatically, it also helps maintain consistency and reduces errors when working with many packages. for teams or individual developers building modular apps, melos is a great tool to include in the workflow.
melos | Dart package
A tool for managing Dart & Flutter repositories with multiple packages (monorepo). Supports automated versioning via…
pub.dev
2. Dio (HTTP client for Dart)
Dio is a powerful HTTP client for Dart and Flutter, perfect for working with network requests. It’s great for handling APIs and covers everything from basic GET/POST requests to more advanced stuff like uploading and downloading files. Dio is especially useful when your app needs more control over its network operations.
It offers a lot of features, like interceptors to handle requests or responses globally, global configuration for things like base URLs and timeouts, and support for multipart form data (helpful for file uploads).
You can also cancel requests and track progress for downloads and uploads. If you’re dealing with complex networking tasks in your app, Dio is definitely a tool you’ll want to check out.
dio | Dart package
A powerful HTTP networking package, supports Interceptors, Aborting and canceling a request, Custom adapters…
pub.dev
3. envied (Environment Variables for Dart with Compile-Time Safety)
The envied package helps you securely manage environment variables in your Dart or Flutter project. It provides compile-time safety, meaning that your environment variables are checked during the compilation process, reducing the risk of runtime errors due to missing or incorrect variables.
With envied, you can access environment variables with type safety and ensure that they are properly defined at build time.
It works by generating code that maps your environment variables into Dart constants, making it easy to work with them in your app. It’s great for managing sensitive data and configurations across different environments, and it ensures you’re always working with the right values, configurations organized.
To use the env package, follow these steps:
Add the package to your pubspec.yaml:
Create a .env file in the root directory of your project:
API_KEY=your_api_key_here
DATABASE_URL=your_database_url_here
3. Define your environment variables in a Dart class:
import 'package:envied/envied.dart';
part 'env.g.dart';
@Envied()
abstract class Env {
static const String apiKey = _Env.apiKey;
static const String dbUrl = _Env.dbUrl;
}atabase URL: $dbUrl');
}
4. Run build_runner to generate the code:
flutter pub run build_runner build
5. Access the environment variables:
void main() {
print(Env.apiKey); // Prints the value of API_KEY from the .env file
print(Env.dbUrl); // Prints the value of DATABASE_URL from the .env file
}
env | Dart package
A starting point for Dart libraries or applications.
pub.dev
4. get_it (Service Locator for Dart and Flutter)
The get_it package is a simple service locator for Dart and Flutter. It’s useful for managing dependencies in a clean and efficient way. Instead of passing objects around manually, you can register and retrieve instances globally using get_it. This helps decouple classes from each other, making your code easier to maintain and test.
It’s commonly used for managing services like network clients, databases, or even global settings that need to be accessed throughout the app.
With get_it, you can register your dependencies once and easily access them from anywhere in your app, which is especially helpful for large projects where dependency management becomes more complex.
Use case in Flutter:
Add the package to your pubspec.yaml:
Set up a service or object to register:
class ApiService {
void fetchData() {
print("Fetching data...");
}
}
3. Register the service in the get_it instance:
import 'package:get_it/get_it.dart';
final getIt = GetIt.instance;
void setup() {
getIt.registerSingleton<ApiService>(ApiService());
}
4. Access the service anywhere in your app:
void main() {
setup(); // Register the services
// Access the ApiService using get_it
getIt<ApiService>().fetchData(); // Prints: Fetching data...
}
With get_it, you can easily manage your app’s dependencies without the need for a heavy framework, making it ideal for both small and large Flutter projects.
get_it | Dart package
Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the…
pub.dev
5. hive_ce (Lightweight and Fast NoSQL Database for Flutter)
hive_ce is a lightweight and fast NoSQL database for Flutter and Dart, ideal for local data storage in mobile apps. It’s a community-maintained fork of Hive with ongoing support, performance improvements, and bug fixes.
hive_ce is perfect for storing structured data such as user preferences, app settings, and other small to medium-sized datasets. It excels in scenarios where offline storage is essential or when a simple, efficient local database is required.
hive_ce is also incredibly fast, uses no native dependencies, and supports encryption, making it a great choice for storing sensitive data in a secure and efficient way.
Simple Use Case in Flutter:
Add the package to your pubspec.yaml:
Initialize Hive and open a box:
import 'package:hive_ce/hive_ce.dart';
import 'package:hive_flutter_ce/hive_flutter_ce.dart';
void main() async {
await Hive.initFlutter();
var box = await Hive.openBox('myBox');
// Store data in the box
box.put('name', 'John Doe');
box.put('age', 30);
// Retrieve data from the box
var name = box.get('name');
var age = box.get('age');
print('Name: $name, Age: $age');
}
3. Close the box when you’re done:
await box.close();
hive_ce | Dart package
Hive Community Edition - A spiritual continuation of Hive v2
pub.dev
6. logger (Simple Logging Utility for Dart and Flutter)
Logger is a simple and handy logging tool for Dart and Flutter projects. It helps you print clean, formatted logs while developing or debugging your app.
Instead of using plain print() statements, logger gives you levels like info, debug, warning, error, and more. This makes it easier to spot issues and organize log output.
You can also customize how the logs appear — with colors, emojis, timestamps, and more. It’s really useful in bigger projects where structured logging helps track down problems faster.
It keeps your console output cleaner and more professional compared to regular print logs. Logger is perfect for development and debugging, helping you keep track of what’s happening in your app in a clean and organized way.
import 'package:logger/logger.dart';
final logger = Logger();
void main() {
logger.i('This is an info message');
logger.w('This is a warning');
logger.e('This is an error');
logger.d('This is a debug log');
}
logger | Dart package
Small, easy to use and extensible logger which prints beautiful logs.
pub.dev
7. freezed (Code Generation for Immutable Data Classes and Unions)
Freezed is a code generator package that helps you create immutable data classes in Dart. It saves you from writing repetitive boilerplate code for things like equality checks, copyWith, toString, and more.
It also supports union types (sealed classes), which makes it super useful for handling things like API states (loading, success, error) in a clean and readable way.
With freezed, your models become easy to manage and more maintainable, especially in large apps. It works well with state management solutions like Bloc, Riverpod, and others. Overall, it helps keep your code neat, clear, and consistent when dealing with data and state.
Add to your pubspec.yaml:
dependencies:
freezed_annotation: ^2.0.0
dev_dependencies:
build_runner: ^2.0.0
freezed: ^2.0.0
2. Create a model using freezed:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
@freezed
class User with _$User {
const factory User({
required String name,
required int age,
}) = _User;
}
3. Run build_runner to generate code:
flutter pub run build_runner build
4. Use your data class:
final user = User(name: 'Alice', age: 25);
final updatedUser = user.copyWith(age: 30);
Freezed makes it super easy to work with models, especially when you want everything to be clean, safe, and less repetitive.
freezed | Dart package
Code generation for immutable classes that has a simple syntax/API without compromising on the features.
pub.dev
8. change_app_package_name (Tool to Change Android Package Name in Flutter)
change_app_package_name is a simple command-line tool that helps you easily change the Android package name of your Flutter project.
Normally, updating the package name involves editing multiple files manually, which can be time-consuming and error-prone. This package automates the process and changes the package name across all the required places in just one step.
It’s super helpful when you want to clone a project, create different versions of an app (like dev or production), or just organize things properly for publishing. Saves a lot of time and avoids manual mistakes.
How to use:
Add the package globally (optional but helpful):
flutter pub global activate change_app_package_name
2. Run the command to change your package name:
flutter pub run change_app_package_name:main com.example.package.name
change_app_package_name | Dart package
Change App Package Name with single command. Update AndroidManifest, build.gradle, MainActivity files & move…
pub.dev
That’s it for now. These packages can really help make your Flutter development smoother and more organized.
Whether you’re handling networking, local storage, environment variables, or managing state, there’s always a package that saves time and avoids writing the same code again and again.
Try them out in your next project — you’ll see the difference. And as always, keep exploring new tools, because Flutter’s ecosystem is growing fast and there’s always something new to learn.