Fast forward a few months, and my project had become a dependency jungle. My builds broke every other day, my app size bloated, and sometimes the exact same code worked on my laptop but failed on my teammate’s machine. 


That’s when I realized something important: 

Dependencies are not just tools. They’re long-term commitments

This blog is about how I went from blindly adding dependencies to carefully managing them like assets, and how that shift completely changed my Flutter development journey. 


The Dependency Trap: My Early Mistakes 


I remember the first time I faced a version conflict. I had added firebaseauth and cloudfirestore to my app. Everything seemed fine until I ran flutter pub get, and then I saw this monster: 


Because every version of cloudfirestore depends on firebasecore ^2.0.0 

and every version of firebaseauth depends on firebasecore ^1.0.0, 

firebaseauth is incompatible with cloudfirestore. 


At that moment, I froze. I didn’t even understand what the error meant. All I wanted was authentication and a database, but suddenly I was debugging dependency graphs like some open-source detective. 


My mistake? I had no dependency strategy. I just added whatever package I found. 


Understanding pubspec.yaml (My Turning Point) 


To fix my problems, I forced myself to study pubspec.yaml deeply. That’s when I learned how powerful (and dangerous) it really is. 


Here’s a simplified breakdown of what I learned: 


environment: 
  sdk: ">=3.0.0 <4.0.0" 
 
dependencies: 
  http: ^1.2.0 
  provider: ^6.1.1 
 
dev_dependencies: 
  flutter_test: 
    sdk: flutter 
  build_runner: ^2.3.3 
  freezed: ^2.3.5 
 
dependency_overrides: 
  firebase_core: ^2.0.0 

 

  • environment → Locks my Dart/Flutter SDK version. This prevents surprises when new Dart versions drop. 
  • dependencies → The core packages my app needs. 
  • devdependencies → Only needed during development (e.g., code generators, test tools). 
  • dependencyoverrides → My “cheat code” when two packages disagree on versions. 

Once I understood this, I realized that managing dependencies is like managing ingredients in a recipe. Too many random spices, and the dish tastes bad. 


Rule #1: Check the Last Update 


I once used a package called fluttercustomtoast. It worked fine, until one day Flutter upgraded and the package broke. When I checked, I saw it hadn’t been updated in 3 years. That’s when I learned my first rule: 


If a package hasn’t been updated in a year or more, I avoid it. 


Today, I only pick dependencies that are actively maintained. 


Rule #2: Don’t Add a Package for Everything 


Early on, I used a package called gradient_button just to get a button with a gradient. Later, I realized I could easily do it myself: 

class GradientButton extends StatelessWidget { 
  final String text; 
  final VoidCallback onPressed; 
 
  const GradientButton({required this.text, required this.onPressed, Key? key}) 
      : super(key: key); 
 
  @override 
  Widget build(BuildContext context) { 
    return InkWell( 
      onTap: onPressed, 
      child: Container( 
        padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), 
        decoration: BoxDecoration( 
          gradient: const LinearGradient( 
            colors: [Color(0xFF6D0EB5), Color(0xFF4059F1)], 
          ), 
          borderRadius: BorderRadius.circular(12), 
        ), 
        child: Center( 
          child: Text( 
            text, 
            style: const TextStyle(color: Colors.white, fontSize: 16), 
          ), 
        ), 
      ), 
    ); 
  } 
} 


That’s less than 30 lines of code! Why should I bloat my project with an extra dependency? 


Now, whenever I think about adding a new package, I ask myself: 

Can I write this in under 50 lines of code? If yes, I skip the dependency. 

 

Rule #3: Favor Flutter Favorites 


Another big shift happened when I discovered Flutter Favorites on pub.dev. These are packages endorsed by the Flutter team because they are well-maintained and widely used. 


Instead of choosing random libraries, I started relying on: 


  • http → For networking 
  • shared_preferences → For local storage 
  • provider or riverpod → For state management 

This gave me more confidence that I wasn’t depending on “abandoned” projects.  


Rule #4: Version Locking with flutter pub outdated 


One of the most frustrating problems I faced was when the app worked on my machine but broke on my teammate’s machine. The reason? We were pulling different versions of the same dependency. 


That’s when I discovered: 


flutter pub outdated 

 

This command showed me exactly which dependencies were old, which had minor updates, and which had major breaking changes. I could then update smartly instead of blindly running flutter pub upgrade


Even better, I started committing the pubspec.lock file to Git. This ensured that every developer (and the CI/CD pipeline) used the exact same dependency versions


Case Study: Cleaning My E-Commerce App 


Let me share a real example. In my e-commerce project, my original pubspec.yaml looked like this: 


dependencies: 
  flutter: 
    sdk: flutter 
  http: ^0.14.0 
  dio: ^5.0.0 
  provider: ^6.1.0 
  riverpod: ^2.3.0 
  firebase_auth: ^5.0.0 
  firebase_core: ^2.0.0 
  firebase_database: ^10.0.0 
  cachednetworkimage: ^3.3.0 
  fancy_buttons: ^1.0.0 
  custom_toasts: ^0.0.5 

 


Problems: 


  1. I was using both http and dio. (Why two networking libraries?) 
  2. I was using both provider and riverpod. (Pick one!) 
  3. fancybuttons and customtoasts were unnecessary – I could build my own. 


After cleaning, here’s my optimized version: 

dependencies: 
  flutter: 
    sdk: flutter 
  dio: ^5.0.0 
  riverpod: ^2.3.0 
  firebase_auth: ^5.0.0 
  firebase_core: ^2.0.0 
  firebase_database: ^10.0.0 
  cachednetworkimage: ^3.3.0 

 

The app became lighter, faster, and easier to maintain. My builds were quicker, and the number of conflicts reduced dramatically.  


Rule #5: Using dependencyoverrides (My Secret Weapon) 


Sometimes, I had no choice but to override versions. For example, when firebaseauth needed firebasecore ^2.0.0 but another package was still stuck on firebasecore ^1.0.0. 


That’s when I discovered this trick: 


dependency_overrides: 
  firebase_core: ^2.0.0  


This forced all packages to use version 2.0.0. It saved me when upgrading to newer Flutter versions, especially during breaking changes. 


Rule #6: Keep Dependencies Lean in CI/CD 


In my CI/CD pipeline, I used to face long build times because Flutter had to fetch 20+ dependencies. After optimizing my dependencies, I reduced builds by 30%


Pro tip: I also cache the .pub-cache folder in CI/CD, so dependencies don’t get redownloaded every time.  


My Final Checklist Before Adding a Dependency 


Now, before I add a dependency, I ask myself: 


  1. Is this package actively maintained? 
  2. Can I build this myself in <50 lines of code? 
  3. Does Flutter already have an alternative? 
  4. Will this package still be useful 2 years from now? 
  5. Does it conflict with any existing dependencies? 

If the answer isn’t convincing, I skip it.  


Conclusion 


Today, when I look at my pubspec.yaml, I don’t see a random list of packages. I see a carefully curated toolkit. Every dependency is chosen with intention, like a craftsman choosing tools. 


When I was a beginner, I thought dependencies made me faster. But now I know: 

The wrong dependencies slow you down more than they help. 

By cleaning my dependencies, I made my apps more scalable, maintainable, and future-proof. And honestly, that’s one of the biggest upgrades I ever gave myself as a Flutter developer. 

Our Trusted
Partner.

Unlock Valuable Cloud and Technology Credits

Imagine reducing your operational costs by up to $100,000 annually without compromising on the technology you rely on. Through our partnerships with leading cloud and technology providers like AWS (Amazon Web Services), Google Cloud Platform (GCP), Microsoft Azure, and Nvidia Inception, we can help you secure up to $25,000 in credits over two years (subject to approval).

These credits can cover essential server fees and offer additional perks, such as:

  • Google Workspace accounts
  • Microsoft accounts
  • Stripe processing fee waivers up to $25,000
  • And many other valuable benefits

Why Choose Our Partnership?

By leveraging these credits, you can significantly optimize your operational expenses. Whether you're a startup or a growing business, the savings from these partnerships ranging from $5,000 to $100,000 annually can make a huge difference in scaling your business efficiently.

The approval process requires company registration and meeting specific requirements, but we provide full support to guide you through every step. Start saving on your cloud infrastructure today and unlock the full potential of your business.

exclusive-partnersexclusive-partners

Let's TALK

Let's TALK and bring your ideas to life! Our experienced team is dedicated to helping your business grow and thrive. Reach out today for personalized support or request your free quote to kickstart your journey to success.

DIGITAL PRODUCTUI/UX DESIGNDIGITAL STUDIOBRANDING DESIGNUI/UX DESIGNEMAIL MARKETINGBRANDING DESIGNUI/UX DESIGNEMAIL MARKETING
DIGITAL PRODUCTUI/UX DESIGNDIGITAL STUDIOBRANDING DESIGNUI/UX DESIGNEMAIL MARKETINGBRANDING DESIGNUI/UX DESIGNEMAIL MARKETING