flutter-di
Skill12 starsChanged 56 days agoMITView on GitHub
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.
In this repository15 other files it gives its agents.
- flutter-accessibilitySkill
- flutter-cachingSkill
- flutter-clean-archSkill
- flutter-concurrencySkill
- flutter-dart-styleSkill
- flutter-design-systemSkill
- flutter-formsSkill
- flutter-monorepoSkill
- flutter-new-moduleSkill
- flutter-runSkill
- flutter-stateSkill
- flutter-store-cdSkill
- flutter-testingSkill
- flutter-themingSkill
- flutter-webSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 36
Add a new static method for the domain group:
- Distinctive: line 138
When a module needs to publish/subscribe events via Broker:
- Very specific: line 150
Always: use i.find<T>() inside Inject factory, never FlutterInjections.get<T>() (which bypasses scope)
- Very specific: line 155
Read core/lib/injections.dart to understand existing registrations
- Distinctive: line 159
Check for circular dependencies before registering
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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
└── HomeConsumerRegistration 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:
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.
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):
context.read<<ModuleName>Controller>()Programmatic resolution (outside widget tree):
final controller = FlutterInjections.get<<ModuleName>Controller>();Inside an Inject factory (chain resolution):
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)
Inject<Get<ModuleName>Usecase>(
(i) => Get<ModuleName>Usecase(i.find<<ModuleName>Repository>()),
),Controller as lazySingleton (stateful, one per scope)
Inject<<ModuleName>Controller>.lazySingleton(
(i) => <ModuleName>Controller(i.find<Get<ModuleName>Usecase>()),
),Repository as singleton (shared data layer)
Inject<<ModuleName>Repository>(
(i) => <ModuleName>RepositoryImpl(i.find<<ModuleName>Datasource>()),
),Event Bus DI
When a module needs to publish/subscribe events via Broker:
Inject<PaymentConsumer>(
(i) => PaymentConsumer(broker: i.find<Broker>()),
),Common Mistakes to Avoid
- Do NOT register controllers in
CoreInjections— they belong in the module scope - Do NOT register usecases as singletons — they are stateless and should be factories
- Always use
i.find<T>()inside Inject factory, neverFlutterInjections.get<T>()(which bypasses scope) - Order matters — list dependencies before dependents in the injections list
Instructions
- Read
core/lib/injections.dartto understand existing registrations - Find the right scope: global (CoreInjections) vs module-scoped (Module.injections)
- Apply the correct lifetime: singleton/lazySingleton/factory
- Register datasource → repository in Core; usecase + controller in Module
- Check for circular dependencies before registering
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

