# Full Guide to CherryPick DI for Dart and Flutter: Dependency Injection with Annotations and Automatic Code Generation
**CherryPick** is a powerful tool for dependency injection in Dart and Flutter projects. It offers a modern approach with code generation, async providers, named and parameterized bindings, and field injection using annotations.
> Tools:
> - [`cherrypick`](https://pub.dev/packages/cherrypick) — runtime DI core
> - [`cherrypick_annotations`](https://pub.dev/packages/cherrypick_annotations) — DI annotations
> - [`cherrypick_generator`](https://pub.dev/packages/cherrypick_generator) — DI code generation
>
---
## CherryPick advantages vs other DI frameworks
- 📦 Simple declarative API for registering and resolving dependencies
- ⚡️ Full support for both sync and async registrations
- 🧩 DI via annotations with codegen, including advanced field injection
- 🏷️ Named bindings for multiple interface implementations
- 🏭 Parameterized bindings for runtime factories (e.g., by ID)
- 🌲 Flexible scope system for dependency isolation and hierarchy
- 🕹️ Optional resolution (`tryResolve`)
- 🐞 Clear compile-time errors for invalid annotation or DI configuration
For most business cases, a single root scope is enough, but CherryPick supports nested scopes:
```dart
final rootScope = CherryPick.openRootScope();
final profileScope = rootScope.openSubScope('profile')
..installModules([ProfileModule()]);
```
- **Subscope** can override parent dependencies.
- When resolving, first checks its own scope, then up the hierarchy.
## Managing names and scope hierarchy (subscopes) in CherryPick
CherryPick supports nested scopes, each can be "root" or a child. For accessing/managing the hierarchy, CherryPick uses scope names (strings) as well as convenient open/close methods.
### Open subScope by name
CherryPick uses separator-delimited strings to search and build scope trees, for example:
```dart
final subScope = CherryPick.openScope(scopeName: 'profile.settings');
```
- Here, `'profile.settings'` will open 'profile' subscope in root, then 'settings' subscope in 'profile'.
- Default separator is a dot (`.`), can be changed via `separator` argument.
**Example with another separator:**
```dart
final subScope = CherryPick.openScope(
scopeName: 'project>>dev>>api',
separator: '>>',
);
```
### Hierarchy & access
Each hierarchy level is a separate scope.
This is convenient for restricting/localizing dependencies, for example:
-`main.profile` — dependencies only for user profile
> **Starting from version 3.0.0**, CherryPick uses a Map-based resolver index for dependency lookup. This means calls to `resolve<T>()`, `tryResolve<T>()` and similar methods are now O(1) operations, regardless of the number of modules or bindings within your scope. Previously it would iterate over all modules and bindings, which could reduce performance as your project grew. This optimization is internal and does not affect the public API or usage patterns, but significantly improves resolution speed for larger applications.
## Automatic resource management: Disposable and dispose
CherryPick makes it easy to clean up resources for your singleton services and other objects registered in DI.
If your class implements the `Disposable` interface, always **await**`scope.dispose()` (or `CherryPick.closeRootScope()`) when you want to free all resources in your scope — CherryPick will automatically await `dispose()` for every object that implements `Disposable` and was resolved via DI.
This ensures safe and graceful resource management (including any async resource cleanup: streams, DB connections, sockets, etc.).
### Example
```dart
class LoggingService implements Disposable {
@override
FutureOr<void> dispose() async {
// Close files, streams, and perform async cleanup here.
final config = await scope.resolveAsync<RemoteConfig>();
```
---
## Validation and diagnostics
- If you use incorrect annotations or DI config, you'll get clear compile-time errors.
- Binding errors are found during code generation, minimizing runtime issues and speeding up development.
---
## Flutter integration: cherrypick_flutter
### What it is
[`cherrypick_flutter`](https://pub.dev/packages/cherrypick_flutter) is the integration package for CherryPick DI in Flutter. It provides a convenient `CherryPickProvider` widget which sits in your widget tree and gives access to the root DI scope (and subscopes) from context.
You can use CherryPick in Dart CLI, server apps, and microservices. All major features work without Flutter.
---
## CherryPick Example Project: Step by Step
1. Add dependencies:
```yaml
dependencies:
cherrypick: ^1.0.0
cherrypick_annotations: ^1.0.0
dev_dependencies:
build_runner: ^2.0.0
cherrypick_generator: ^1.0.0
```
2. Describe your modules using annotations.
3. To generate DI code:
```shell
dart run build_runner build --delete-conflicting-outputs
```
4. Enjoy modern DI with no boilerplate!
---
## Conclusion
**CherryPick** is a modern DI solution for Dart and Flutter, combining a concise API and advanced annotation/codegen features. Scopes, parameterized providers, named bindings, and field-injection make it great for both small and large-scale projects.