Skip to content
Back to skills

Flutter Di

ASecurity

Use when registering or resolving a dependency with flutter_injections - adding a registration to the core injections, assembling a feature FlutterModule, choosing between singleton/lazySingleton/factory, or calling FlutterInjections.get. Triggers on a runtime "dependency not registered" error.

  • 11 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agents

Security analysis

A100/100

Scanned September 24, 2026

npx -y skills add gabuldev/flutter-skills --skill flutter-di --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Flutter Di?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Flutter Di
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gabuldev-flutter-di/badge)](https://www.skillsdirectory.com/skills/gabuldev-flutter-di)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: flutter-di
description: Use when registering or resolving a dependency with flutter_injections - adding a registration to the core injections, assembling a feature FlutterModule, choosing between singleton/lazySingleton/factory, or calling FlutterInjections.get. Triggers on a runtime "dependency not registered" error.
---

You are configuring dependency injection for a Flutter feature using `flutter_injections`.

## DI Architecture Overview

```
FlutterInjectionsWidget (root, in AppWidget)
  └── CoreInjections.core()        ← global singletons (Dio, repos, session)
       ├── auth()
       ├── services()
       ├── eventBus()
       └── ...

FlutterModule (per-module, lazy)
  └── HomeModule.injections        ← scoped to module lifetime
       ├── HomeController
       └── HomeConsumer
```

## Registration Lifetimes

| Type | Usage | Pattern |
|------|-------|---------|
| `singleton` | One instance for app lifetime | Dio, Session, Broker |
| `lazySingleton` | Created on first use, then kept | Controllers, Repositories |
| `factory` | New instance every `get<T>()` call | Usecases, one-time actions |

## Step 1: Register in CoreInjections

File: `core/lib/injections.dart`

Add a new static method for the domain group:

```dart
class CoreInjections {
  static List<Inject<Object>> core() => [
    ...auth(),
    ...services(),
    ...eventBus(),
    ...<module_name>(),  // ← ADD THIS
  ];

  // ← ADD THIS METHOD
  static List<Inject<Object>> <module_name>() => [
    Inject<<ModuleName>Datasource>(
      (i) => <ModuleName>Datasource(i.find<Dio>()),
    ),
    Inject<<ModuleName>Repository>(
      (i) => <ModuleName>RepositoryImpl(i.find<<ModuleName>Datasource>()),
    ),
  ];
}
```

## Step 2: Register controller in the Module

File: `modules/<module_name>/<module_name>_module.dart`

Extend **`FlutterModule`** and override its two getters, `injections` and
`child`. `FlutterModule` is a `StatelessWidget` that wraps its `child` in a
`FlutterInjectionsWidget` for you — don't build that wrapper by hand.

```dart
class <ModuleName>Module extends FlutterModule {
  const <ModuleName>Module({super.key});

  @override
  List<Inject<Object>> get injections => [
        Inject<<ModuleName>Controller>.lazySingleton(
          (i) => <ModuleName>Controller(
            Get<ModuleName>Usecase(i.find<<ModuleName>Repository>()),
          ),
        ),
      ];

  @override
  Widget get child => BlocProvider(
        create: (_) => FlutterInjections.get<<ModuleName>Controller>(),
        child: const <ModuleName>Screen(),
      );
}
```

Both getters are `@override` — they are abstract on `FlutterModule`, so
omitting either is a compile error rather than a silent no-op.

## Step 3: Resolve dependencies

**In widgets/screens (via BlocProvider):**
```dart
context.read<<ModuleName>Controller>()
```

**Programmatic resolution (outside widget tree):**
```dart
final controller = FlutterInjections.get<<ModuleName>Controller>();
```

**Inside an Inject factory (chain resolution):**
```dart
Inject<OrderController>.lazySingleton(
  (i) => OrderController(
    getOrders: i.find<GetOrdersUsecase>(),
    broker:    i.find<Broker>(),
  ),
),
```

## Patterns to Follow

### Usecase as factory (stateless, safe to create per-use)
```dart
Inject<Get<ModuleName>Usecase>(
  (i) => Get<ModuleName>Usecase(i.find<<ModuleName>Repository>()),
),
```

### Controller as lazySingleton (stateful, one per scope)
```dart
Inject<<ModuleName>Controller>.lazySingleton(
  (i) => <ModuleName>Controller(i.find<Get<ModuleName>Usecase>()),
),
```

### Repository as singleton (shared data layer)
```dart
Inject<<ModuleName>Repository>(
  (i) => <ModuleName>RepositoryImpl(i.find<<ModuleName>Datasource>()),
),
```

## Event Bus DI

When a module needs to publish/subscribe events via Broker:

```dart
Inject<PaymentConsumer>(
  (i) => PaymentConsumer(broker: i.find<Broker>()),
),
```

## Common Mistakes to Avoid

1. **Do NOT** register controllers in `CoreInjections` — they belong in the module scope
2. **Do NOT** register usecases as singletons — they are stateless and should be factories
3. **Always** use `i.find<T>()` inside Inject factory, never `FlutterInjections.get<T>()` (which bypasses scope)
4. **Order matters** — list dependencies before dependents in the injections list

## Instructions

1. Read `core/lib/injections.dart` to understand existing registrations
2. Find the right scope: global (CoreInjections) vs module-scoped (Module.injections)
3. Apply the correct lifetime: singleton/lazySingleton/factory
4. Register datasource → repository in Core; usecase + controller in Module
5. Check for circular dependencies before registering

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.