What are GetX Bindings?
Bindings in GetX are classes that handle dependency injection for specific routes. They define which controllers and services should be created when a route is opened, and they automatically clean them up when the route is closed. This promotes better code organization, lazy loading, and prevents memory leaks.
Why Use Bindings?
- Separation of Concerns – Keep dependency registration separate from UI code.
- Automatic Lifecycle – Controllers are disposed when the route is popped (unless marked permanent).
- Lazy Loading – Dependencies are created only when the route is actually visited.
- Testability – Easily mock dependencies for unit tests.
- Cleaner Code – No scattered
Get.putcalls inside widgets.
Creating a Basic Binding
A binding is a class that implements the Bindings interface and overrides the dependencies() method.
Using Bindings with GetPage
Bindings are typically used with named routes in GetMaterialApp.
Initial Binding (App-Level)
You can also set an initial binding that runs when the app starts. This is useful for global dependencies like authentication services, theme managers, or local storage.
Binding with Multiple Controllers
A single binding can register multiple controllers and services.
Binding Lifecycle
When a route with a binding is opened:
- The binding's
dependencies()method is called. - Controllers are registered (but not instantiated if using
lazyPut). - The page widget is built.
- When a controller is accessed (e.g., via
Get.find()orGetView), it is instantiated. - When the route is popped, GetX checks if the controllers are marked
permanent; if not, they are disposed (andonClose()is called).
Binding with Parameters
You can pass parameters to bindings using GetPage with binding that takes arguments.
Nested Bindings & Dependency Injection
For complex apps, you can nest bindings or inject dependencies that themselves depend on others.
Bindings vs Direct Get.put
| Aspect | Bindings | Direct Get.put |
|---|---|---|
| Place of registration | Separate class, defined per route | Inside widgets or main |
| Lazy loading | Yes (default with lazyPut) | Controlled by developer |
| Lifecycle | Auto-dispose on route pop | Manual or permanent |
| Testability | Easy to mock via binding | Requires resetting dependencies |
| Code organization | Centralized per feature | Scattered across files |
Bindings are recommended for large apps with many routes, as they provide a clear separation and automatic cleanup. For small apps, Get.put directly in main may suffice.
Best Practices
- One binding per route – Keep dependencies grouped by feature or screen.
- Use
lazyPutby default – Improves startup performance; instantiate only when needed. - Inject dependencies via constructors – Makes testing easier and clarifies dependencies.
- Avoid heavy work in binding – Keep binding only for registration; move initialization to controller's
onInit. - Use initial binding for truly global services – Like API clients, database helpers, theme managers.
- Name bindings consistently – e.g.,
HomeBinding,ProfileBindingto match route names.
Common Mistakes
- ❌ Calling
Get.putinside a binding without lazy – Can still work, but lazy is generally better. ✅ UseGet.lazyPutunless you need the instance immediately. - ❌ Forgetting to dispose of stream subscriptions – Controllers are disposed, but you still need to clean up manually in
onClose. ✅ Always overrideonCloseto dispose listeners. - ❌ Creating bindings inside build methods – Causes re-creation of binding objects.
✅ Define bindings as separate classes or use
GetPagewith constant references. - ❌ Overusing permanent controllers – Can cause memory leaks if they hold onto resources.
✅ Use
permanent: trueonly for truly global dependencies.
Conclusion
GetX bindings provide a powerful, route-centric way to manage dependencies. They improve code structure, performance, and lifecycle management. By adopting bindings, you ensure that your controllers are created and disposed at the right time, leading to cleaner, more maintainable Flutter apps.