{"id":32282646,"url":"https://github.com/pschiffmann/zone_di.dart","last_synced_at":"2026-02-23T17:03:14.790Z","repository":{"id":45109435,"uuid":"202919170","full_name":"pschiffmann/zone_di.dart","owner":"pschiffmann","description":"Dependency injection with a functional API that works without code generation, mirrors or passing around Injector objects.","archived":false,"fork":false,"pushed_at":"2022-01-07T07:22:22.000Z","size":17,"stargazers_count":5,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-23T01:06:17.905Z","etag":null,"topics":["dependency-injection"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/zone_di","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pschiffmann.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-17T18:38:58.000Z","updated_at":"2024-06-17T19:48:40.000Z","dependencies_parsed_at":"2022-08-29T06:50:47.978Z","dependency_job_id":null,"html_url":"https://github.com/pschiffmann/zone_di.dart","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pschiffmann/zone_di.dart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pschiffmann%2Fzone_di.dart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pschiffmann%2Fzone_di.dart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pschiffmann%2Fzone_di.dart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pschiffmann%2Fzone_di.dart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pschiffmann","download_url":"https://codeload.github.com/pschiffmann/zone_di.dart/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pschiffmann%2Fzone_di.dart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29748803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T07:44:07.782Z","status":"ssl_error","status_checked_at":"2026-02-23T07:44:07.432Z","response_time":90,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection"],"created_at":"2025-10-23T01:03:59.135Z","updated_at":"2026-02-23T17:03:14.785Z","avatar_url":"https://github.com/pschiffmann.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zone_di\n\nAn inversion of control package with a functional API that works without code generation, mirrors or passing around Injector objects.\n\n## API overview\n\nThe three main exports of this package are `Token`, `provide()` and `inject()`.\nUse tokens to declare dependencies that can be injected.\n\n```dart\nfinal greetingToken = Token\u003cString\u003e('my_package.greeting');\nfinal emphasisToken = Token\u003cint\u003e('my_package.emphasis');\n```\n\nUnlike many other dependency injection frameworks, this package doesn't expose a _Container_ or _Injector_ class from which dependencies could be obtained.\nInstead, the current value of a token can be looked up with a call to the top-level function `inject()`.\n\n```dart\nclass Greeter {\n  Greeter()\n      : greeting = inject(greetingToken),\n        emphasis = inject(emphasisToken);\n\n  final String greeting;\n  final int emphasis;\n\n  void greet(String name) {\n    print('$greeting, $name${\"!\" * emphasis}');\n  }\n}\n```\n\nValues are made available for injection by passing them to the top-level function `provide()`, together with a context callback function.\nThe function will be called immediately, and the (token, value) associations exist only inside of the context of this call tree.\n\n```dart\nvoid main() {\n  provide({\n    greetingToken: 'Hello',\n    emphasisToken: 1,\n  }, () {\n    Greeter().greet('world'); // 'Hello, world!'\n  });\n\n  Greeter().greet('you'); // throws: `MissingDependencyException`, because the\n                          // `inject()` call inside of the `Greeter` constructor\n                          // was made outside of a `provide()` context.\n                          // The previously provided values don't leak out from\n                          // their context.\n}\n```\n\nDifferent values can be provided to different parts of the program for the same token.\n`provide()` contexts can be nested, and inner values shadow outer ones for the same token.\nIn this way, token lookup works analogous to name lookup in functions (local variable shadows function parameter, shadows class property, shadows global variable), except that it works across the boundaries of the current function.\n\n```dart\nvoid main() {\n  provide({\n    greetingToken: 'Hello',\n    emphasisToken: 1,\n  }, () {\n    provide({greetingToken: 'Good day'}, () {\n      Greeter().greet('Philipp'); // 'Good day, Philipp!'\n    });\n\n    provide({emphasisToken: 3}, () {\n      Greeter().greet('Paul'); // 'Hello, Paul!!!'\n    });\n  });\n}\n```\n\nNotice that this even works for asynchronous code – multiple `provide()` contexts can be executed concurrently without values leaking from one context into the other.\n\n```dart\nFuture delay1Sec() =\u003e Future.delayed(Duration(seconds: 1));\n\n/// Will print:\n///\n///     Hello, Alice!\n///     Goodbye, Alice!\n///     Hello, Bob!\n///     Goodbye, Bob!\n///     Hello, John!\n///     Goodbye, John!\nvoid main() {\n  provide({emphasisToken: 1}, () {\n    final names = ['Alice', 'Bob', 'John'];\n\n    provide({greetingToken: 'Hello'}, () async {\n      final greeter = Greeter();\n      for (final name in names) {\n        greeter.greet(name);\n        await delay1Sec();\n      }\n    });\n\n    provide({greetingToken: 'Goodbye'}, () async {\n      final greeter = Greeter();\n      await Future.delayed(Duration(milliseconds: 500));\n      for (final name in names) {\n        greeter.greet(name);\n        await delay1Sec();\n      }\n    });\n  });\n}\n```\n\nFinally, there's also `provideFactories()` that constructs token values from the given factory functions and handles dependencies between the factories.\nFor more details on that and the other functions, see the [API docs](https://pub.dev/documentation/zone_di/latest/).\n\n## How it works\n\nTo make `provide()` arguments available in `inject()`, this package uses [zones](https://api.dartlang.org/stable/dart-async/Zone-class.html).\nThat means it can avoid global mutable state and the edge cases that typically come with it.\nFor a longer explanation, I wrote a blog post about it [here](https://medium.com/@philippschiffmann/dependency-injection-in-dart-using-zones-45d6028eb1da).\n\n## A note on naming\n\nSince writing this package I have learned that the name \"dependency injection\" explicitly refers to the approach to use a _Container_ for managing objects, and that the dependencies of a class should be visible from its public API, mainly its constructor parameters or public setters.\nSince this API doesn't follow these conventions, the _di_ in the package name is a misnomer, and I'm sorry if I've lured you onto this README with false promises.\nI hope it can be of use to you regardless.\n\n## How to use this package / best practices\n\nHere are a few tips in no particular order.\n\n---\n\nIf you're already using a framework that ships with a dependency injection mechanism, that one is probably better optimized for your use case.\nIn particular, Angular has its own [annotation-based DI system](https://angulardart.dev/guide/hierarchical-dependency-injection), and Flutter has [inherited widgets](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html).\nBoth support multiple concurrent, nested scopes likes this package; but scopes are tied to components/widgets rather than function calls, which is most likely what you want.\n\nInstead, consider using this package if you're writing command line applications, or pub packages that can be consumed on all platforms (Flutter, web, server).\n\n---\n\nYou can use `inject()` not only inside of class constructors, but also in individual methods or even top-level functions outside of any class.\n\n---\n\nThe return value of the context function is passed through by `provide()`.\nYou can use this to instantiate a single class or call a single function that `inject()`s values:\n\n```dart\nvoid main() {\n  final greeter =\n      provide({greetingToken: 'Hello', emphasisToken: 1}, () =\u003e Greeter());\n\n  greeter.greet('world'); // `greeter` can now be used outside of the context\n                          // function.\n}\n```\n\n---\n\nOther people can't see what your classes and functions `inject()`.\nMake sure to explicitly list all dependencies of your class or function in its doc comment!\nRemember to also include transitive dependencies – if your function instantiates a class with a dependency on `fooToken`, and your function doesn't provide a value for it, then your function should also list that token as its dependency.\n\n---\n\nIf you use zone_di in your published pub packages and expose the injection to the package consumer, consider writing your own specialized `provide()` function like this:\n\n```dart\nimport 'package:meta/meta.dart' show required;\nimport 'package:zone_di/zone_di.dart' as zone_di;\n\nfinal fooToken = Token\u003cString\u003e('my_package.foo');\nfinal barToken = Token\u003cint\u003e('my_package.bar');\n\nvoid provide(void Function() f, {@required String foo, int bar}) {\n  zone_di.provide({fooToken: foo, barToken: bar}, f);\n}\n```\n\nThis way, a consumer of your package doesn't have to look up what `Token`s are, and gets a type-safe list of all of your public dependencies at a glance.\n\n## Special thanks\n\nA big thank you goes to Paul Hammant for his insightful feedback and criticism.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpschiffmann%2Fzone_di.dart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpschiffmann%2Fzone_di.dart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpschiffmann%2Fzone_di.dart/lists"}