This content originally appeared on DEV Community and was authored by Hitesh Meghwal
As mobile developers, we've all hit that point where our app starts small… but then features stack up, services multiply, and suddenly you're wrestling with a monster.
That's where Dependency Injection (DI) steps in as a lifesaver.
🔍 What is Dependency Injection in flutter?
In simple terms, DI is a design pattern that helps you supply an object’s dependencies from the outside, instead of creating them inside the object.
In this app, we’re handling Dependency Injection (DI) using the GetIt package — a popular service locator in Dart and Flutter.
GetIt acts as a central registry where you can register services (like Auth, API handlers, databases, etc.) and retrieve them anywhere in the app — without having to manually pass them down through constructors.
It's a general-purpose DI solution designed to keep your code clean, decoupled, and scalable. Whether you're working with state management, API layers, or storage services, GetIt helps manage those dependencies efficiently.
Let’s go with simple example:
🍽️ Dependency Injection Explained Like Room Service
Let’s say you're staying at a hotel.
Whenever you're hungry, you don’t go to the kitchen, find the chef, gather ingredients, and cook for yourself. Instead, you just call room service.
You don’t care how the food is made — you only care that it arrives on time and works.
Now imagine you have 100 rooms and each room has its own private kitchen doing everything from scratch. That’s:
- Expensive
- Messy
- Impossible to manage at scale
Instead, the hotel has:
- One centralized kitchen (your service)
- A delivery system (your dependency injection framework)
- Every room request food (uses the service) when needed
Let’s see how to implement in Flutter app:
🛠️ What We’ll Cover
- ✅ Add get_it to pubspec.yaml
- 📦 Define services (like AuthService)
- 🔁 Setup GetIt with registerSingleton and registerFactory
- 🧪 Use DI in UI classes
🧩 Pattern explanation: when to use factory vs singleton
pubspec.yaml
dependencies:
flutter:
sdk: flutter
get_it: ^8.0.3
Then run:
flutter pub get
- Create a Service
// lib/services/auth_service.dart
class AuthService {
void login() {
print("User logged in via AuthService");
}
}
- Setup GetIt (Dependency Injection Configuration)
// lib/di/injection.dart
import 'package:get_it/get_it.dart';
import '../services/auth_service.dart';
final getIt = GetIt.instance;
void setupLocator() {
// Register Singleton (one shared instance)
getIt.registerLazySingleton<AuthService>(() => AuthService());
// If you want a new instance every time, use registerFactory:
// getIt.registerFactory<AuthService>(() => AuthService());
}
Now, in main.dart, initialize it:
void main() {
setupLocator();
runApp(MyApp());
}
- Using the Injected Service
// lib/screens/login_screen.dart
import 'package:flutter/material.dart';
import '../di/injection.dart';
import '../services/auth_service.dart';
class LoginScreen extends StatelessWidget {
final AuthService _authService = getIt<AuthService>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_authService.login();
},
child: Text("Login"),
),
),
);
}
}
When BLoC + Cubit (via BlocProvider)
• When using Flutter BLoC, you can inject dependencies via BlocProvider.
• Can be used like DI for blocs or services.
BlocProvider(
create: (_) => AuthCubit(authService),
child: LoginScreen(),
)
- When to Use registerSingleton vs registerFactory
Pattern | Use Case | Code Example |
---|---|---|
registerSingleton |
Use when the object must persist | getIt.registerSingleton<AuthService>(...) |
registerLazySingleton |
Same as singleton, but lazy-loaded | getIt.registerLazySingleton<AuthService>(...) |
registerFactory |
Use when you need a new instance each time | getIt.registerFactory<AuthService>(...) |
🧩 Example: Singleton vs Factory
🔁 Singleton Example (Global Auth, Shared Instance)
- getIt.registerLazySingleton(() => AuthService()); → Same AuthService instance used across the entire app
🔄 Factory Example (Fresh Object)
- getIt.registerFactory(() => AuthService()); → Each time you call getIt(), a new object is returned
✅ Wrap-up all things
GetIt is your app’s room service system — widgets just ask for what they need and GetIt delivers!
By using:
- registerLazySingleton or registerSingleton for shared services (Auth, API, Storage)
- registerFactory for short-lived or per-screen classes (Controllers, Blocs)
🧩 Conclusion
When you're building small prototypes, you might not need DI. But as your app becomes real-world, team-based, and multi-featured, DI becomes essential.
It’s not just about "clean code" — it's about:
• Easier maintenance
• Faster onboarding for new devs
• Confidence in refactoring
• Robust unit testing
If your app is getting complex,
dependency injection isn't optional—it's foundational.
This content originally appeared on DEV Community and was authored by Hitesh Meghwal

Hitesh Meghwal | Sciencx (2025-07-12T21:25:29+00:00) What if your app could get what it needs—without building everything itself? That’s the magic of dependency injection in App.. Retrieved from https://www.scien.cx/2025/07/12/what-if-your-app-could-get-what-it-needs-without-building-everything-itself-thats-the-magic-of-dependency-injection-in-app/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.