Dependency Injection Setup (Injectable) in Flutter App
injectable is a code generator on top of GetIt. You write annotations, build_runner generates registration code. Instead of manual injection_container.dart with 300 lines — clean declarative code with @injectable, @singleton, @lazySingleton.
Why Injectable if GetIt Exists
Manual GetIt registration doesn't scale: with 50+ dependencies need track registration order, not forget to update injection_container on refactoring, parse other's custom files. injectable eliminates this manual work — add annotation to class, run build_runner, *.config.dart file updates automatically.
Basic Setup
pubspec.yaml:
dependencies:
get_it: ^7.6.0
injectable: ^2.3.0
dev_dependencies:
injectable_generator: ^2.4.0
build_runner: ^2.4.0
Entry point:
// injection.dart
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'injection.config.dart';
final sl = GetIt.instance;
@InjectableInit()
Future<void> configureDependencies() => sl.init();
Service annotation:
@lazySingleton
class ApiService {
final Dio _dio;
ApiService(this._dio); // injectable figures out Dio automatically
}
Run generation: dart run build_runner build --delete-conflicting-outputs.
Environments: dev, staging, production
injectable supports @Environment annotations — one of main reasons to choose it over pure GetIt:
@dev
@LazySingleton(as: ApiService)
class MockApiService implements ApiService { ... }
@prod
@LazySingleton(as: ApiService)
class RealApiService implements ApiService { ... }
Initialization with environment:
await configureDependencies(environment: Environment.prod);
In tests — Environment.dev with mocks. No need to build conditions in injection_container.
Async Dependencies
@singleton
class DatabaseService {
late final Database _db;
@factoryMethod
static Future<DatabaseService> create() async {
final service = DatabaseService();
service._db = await openDatabase('app.db');
return service;
}
}
@factoryMethod on static async constructor — injectable generates registerSingletonAsync. configureDependencies() returns Future, need await before runApp.
Common Code Generation Problem
After adding new @injectable class developer forgets to run build_runner — app compiles (old .config.dart not deleted), but new class not registered. On first access — StateError: No instance of type XxxService found. Solution: add build_runner watch to development process or setup CI step to check generated code freshness.
What's Included in Setup
Add dependencies → create entry point with @InjectableInit → annotate existing services and repositories → setup environments for dev/prod → configure build_runner in CI → check async dependencies. If needed — refactor manual injection_container to annotations.
Work takes 1–3 days depending on project size. On new project faster, on existing with manual DI — longer due to migration.







