flutter
/

GetX Get.put: The Complete Guide to Immediate Dependency Injection

Last Sync: Today

On this page

13
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

GetX Get.put: The Complete Guide to Immediate Dependency Injection

What is Get.put?

Get.put is the primary method in GetX for immediate dependency injection. It creates an instance of a class (usually a controller or service) and makes it available throughout your app. Unlike Get.lazyPut, the instance is created right away, not lazily on first access. This is perfect for dependencies that you know will be needed soon, or for global services that must be ready immediately.

Basic Syntax

DARTRead-only
1
// Simple injection
Get.put(MyController());

// Store the instance
final controller = Get.put(MyController());

// Later, retrieve anywhere
final controller = Get.find<MyController>();

Returning the Instance

Get.put returns the instance you just created, so you can store it directly for later use. This is common in views to have a typed reference without needing Get.find.

DARTRead-only
1
class HomePage extends StatelessWidget {
  final controller = Get.put(HomeController());

  @override
  Widget build(BuildContext context) {
    return Obx(() => Text('${controller.count}'));
  }
}

Permanent Controllers

By default, controllers injected with Get.put are not permanent – they will be disposed when the route that created them is popped, unless you set permanent: true. Use this for global services that should live the entire app lifecycle.

DARTRead-only
1
// Permanent – never disposed automatically
Get.put(MyController(), permanent: true);

// Also works with lazyPut
Get.lazyPut(() => MyController(), permanent: true);

Using Tags for Multiple Instances

If you need multiple instances of the same type, you can give each a unique tag. This allows you to differentiate them when using Get.find.

DARTRead-only
1
// Register two instances of UserController with different tags
Get.put(UserController(), tag: 'user1');
Get.put(UserController(), tag: 'user2');

// Retrieve the specific one
final user1 = Get.find<UserController>(tag: 'user1');
final user2 = Get.find<UserController>(tag: 'user2');

Injection with Bindings

In a binding, you can also use Get.put if you need the instance immediately. However, Get.lazyPut is often preferred for better startup performance.

DARTRead-only
1
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    // Immediate injection
    Get.put(HomeController());
    // Or lazy (recommended)
    Get.lazyPut(() => ApiService());
  }
}

Get.put vs Get.lazyPut

  • Get.put – Creates instance immediately. Use when the dependency is needed right away or you want the instance to be ready even if never accessed.
  • Get.lazyPut – Creates instance only on first Get.find. Use for better startup performance when the dependency might not be used immediately.

Get.put vs Get.create

  • Get.put – Creates a singleton instance. Each Get.find returns the same instance.
  • Get.create – Creates a new instance every time Get.find is called. Useful for transient dependencies.

Checking Registration

Before using Get.find, you can check if an instance is already registered to avoid errors.

DARTRead-only
1
if (!Get.isRegistered<MyController>()) {
  Get.put(MyController());
}
final controller = Get.find<MyController>();

Best Practices

  • Use Get.put in initState or bindings – Avoid placing it directly in the build method to prevent duplicate instances on rebuilds.
  • Prefer Get.lazyPut for most cases – It improves startup performance, especially for routes that may not be visited.
  • Use permanent: true sparingly – Only for truly global dependencies (e.g., authentication service, theme manager).
  • Use tags when you need multiple instances – For example, in a list of items where each item has its own controller.
  • Inject dependencies via constructor – Even with Get.put, you can pass dependencies to the controller's constructor for better testability.

Common Mistakes

  • ❌ Calling Get.put inside build method – Creates a new instance on every rebuild. ✅ Place it in initState of a StatefulWidget, or better, use bindings.
  • ❌ Forgetting to check isRegistered before Get.put – Can accidentally overwrite existing instances. ✅ Use Get.isRegistered or rely on the framework to ensure you don't duplicate.
  • ❌ Using Get.put when you need multiple instances – Overwrites the previous one. ✅ Use tags to distinguish instances.
  • ❌ Not disposing resources in onClose – Even with permanent controllers, you should clean up listeners.

FAQ

  • Q: When should I use Get.put vs Get.lazyPut?
    A: Use Get.put if you need the instance immediately (e.g., in the initial binding of a route that will be accessed). Use Get.lazyPut for most other cases to defer creation until needed.
  • Q: Can I use Get.put inside a controller?
    A: Yes, but be careful about circular dependencies. It's better to inject dependencies via the controller's constructor and register them in bindings.
  • Q: What happens if I call Get.put twice for the same type?
    A: The second call will overwrite the first if no tag is used. Use Get.isRegistered to check before re-registering.
  • Q: How do I remove an instance registered with Get.put?
    A: Use Get.delete<MyController>() (optionally with a tag). This will also call the controller's onClose.
  • Q: Does Get.put automatically dispose the controller?
    A: By default, it is tied to the route's lifecycle. When the route is popped, the controller is disposed unless permanent: true is set.

Conclusion

Get.put is a simple yet powerful method for immediate dependency injection in GetX. It gives you fine control over when dependencies are created, and combined with tags and permanence, it handles everything from simple controllers to complex global services. When used judiciously, it contributes to clean, maintainable Flutter applications.

Try it yourself

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: HomePage(),
    );
  }
}

class CounterController extends GetxController {
  var count = 0.obs;
  void increment() => count++;

  @override
  void onClose() {
    print('CounterController disposed');
    super.onClose();
  }
}

class HomePage extends StatelessWidget {
  // Get.put creates the instance immediately and returns it
  final controller = Get.put(CounterController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Get.put Example')),
      body: Center(
        child: Obx(() => Text(
          'Count: ${controller.count}',
          style: TextStyle(fontSize: 32),
        )),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 3

What does Get.put do?

A
Creates a lazy instance
B
Creates an instance immediately and registers it
C
Creates a new instance every time
D
Deletes an instance
Q2
of 3

How can you create a permanent controller that never gets disposed?

A
Get.put(MyController(), permanent: true)
B
Get.lazyPut(MyController(), permanent: true)
C
Both of the above
D
None of the above
Q3
of 3

What is the purpose of the `tag` parameter in Get.put?

A
To set a name for debugging
B
To allow multiple instances of the same type
C
To make the controller permanent
D
To dispose the controller automatically

Previous

getx dependency injection

Next

getx lazyput

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.