flutter
/

GetX Get.lazyPut: Lazy Dependency Injection in Flutter

Last Sync: Today

On this page

11
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

GetX Get.lazyPut: Lazy Dependency Injection in Flutter

What is Get.lazyPut?

Get.lazyPut is a method in GetX that registers a dependency but defers its creation until it is first accessed. This is in contrast to Get.put, which creates the instance immediately. Lazy injection is ideal for improving startup performance and for dependencies that may not be used in every session of your app.

Basic Syntax

DARTRead-only
1
Get.lazyPut<MyController>(() => MyController());

// The instance is NOT created yet
// It will be created only when this line runs:
final controller = Get.find<MyController>();

How It Works

When you call Get.lazyPut, GetX stores a factory function that creates the instance. The actual object is not instantiated until you (or GetX internally) call Get.find for that type. After that, the instance is cached and reused for subsequent Get.find calls.

When to Use Get.lazyPut

  • Improve startup time – Avoid creating many controllers at once when the app launches.
  • Optional dependencies – Controllers that are only needed under certain conditions (e.g., admin features).
  • Routes with bindings – In GetPage bindings, using lazyPut ensures controllers are created only when the route is visited.
  • Large services – Heavy initialisation (e.g., database connections) should be lazy to avoid blocking the UI.

Parameters

The fenix (phoenix) flag, when set to true, allows the instance to be recreated after it has been disposed. This is useful for dependencies that you want to be able to resurrect without re-registering manually.

DARTRead-only
1
Get.lazyPut<MyController>(
  () => MyController(),
  fenix: true,
);
// If the controller is disposed (e.g., route popped), the next Get.find will create a new one automatically.

Setting permanent: true prevents the instance from ever being disposed automatically. This is similar to using Get.put with permanent: true, but the instance is still created lazily.

DARTRead-only
1
Get.lazyPut<MyController>(
  () => MyController(),
  permanent: true,
);
// The instance will live for the entire app lifecycle, but only created on first access.

Use tags to register multiple instances of the same type. Each tag creates a separate lazy registration.

DARTRead-only
1
Get.lazyPut<UserController>(() => UserController('Alice'), tag: 'alice');
Get.lazyPut<UserController>(() => UserController('Bob'), tag: 'bob');

final alice = Get.find<UserController>(tag: 'alice');
final bob = Get.find<UserController>(tag: 'bob');

Get.lazyPut vs Get.put

Using with Bindings

The most common pattern is to use Get.lazyPut inside a binding. This ensures that controllers are only created when the route is actually opened.

DARTRead-only
1
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(() => HomeController());
    Get.lazyPut<ApiService>(() => ApiService());
  }
}

GetPage(
  name: '/home',
  page: () => HomeView(),
  binding: HomeBinding(),
);

Best Practices

  • Prefer lazyPut in bindings – Defer creation until the route is visited.
  • Use fenix: true for disposable controllers – Allows recreation after route disposal without re-registration.
  • Avoid using lazyPut for truly global dependencies – Use Get.put(permanent: true) instead if you need the instance immediately.
  • Don't overuse permanent – Let GetX dispose controllers automatically when possible.
  • Check registration before find – Use Get.isRegistered to avoid errors when you're not sure if the dependency is registered yet.

Common Mistakes

  • ❌ Calling Get.find before any registration – Throws an error. ✅ Always register first, or check with Get.isRegistered.
  • ❌ Using lazyPut when you need the instance immediately after registration – The instance won't exist yet. ✅ Use Get.put instead.
  • ❌ Forgetting to set fenix: true for re‑usable controllers – After disposal, they won't be recreated. ✅ Set fenix: true if you want them to come back to life.
  • ❌ Assuming lazyPut creates a new instance each time – It's still a singleton; use Get.create for fresh instances.

FAQ

  • Q: Can I use Get.lazyPut without Get.find?
    A: Yes, you can register a dependency that may never be used. It will simply never be created.
  • Q: What happens if I call Get.lazyPut multiple times with the same type?
    A: Unless you use different tags, the later registration overwrites the earlier one. You can check with Get.isRegistered first.
  • Q: How do I know if a lazy instance has been created?
    A: Use Get.isRegistered<MyController>(). It returns true once the instance has been created (or if it was registered but not yet created? Actually, isRegistered returns true as soon as the lazy registration is made, because the dependency is "registered", even if the instance is not yet created. To know if the instance exists, you can check internally, but for most use cases you don't need to distinguish.
  • Q: Can I convert a lazy registration to a permanent one later?
    A: No, once registered, you cannot change its flags. You would need to delete and re‑register.
  • Q: Is Get.lazyPut thread‑safe?
    A: Yes, GetX is designed for Flutter's single-threaded UI environment.

Conclusion

Get.lazyPut is an essential tool for efficient dependency management in GetX. By deferring creation until the first use, you can significantly improve your app's startup time and reduce memory footprint. Combined with bindings, fenix, and tags, it provides a flexible and powerful way to manage dependencies in large 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 onInit() {
    super.onInit();
    print('CounterController created');
  }

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Register lazily – no instance is created yet
    Get.lazyPut<CounterController>(() => CounterController());

    // Print status: should be false because the instance hasn't been accessed yet
    // You can't see this output in the UI but it will appear in the console.
    print('Is registered? ${Get.isRegistered<CounterController>()}'); // true

    return Scaffold(
      appBar: AppBar(title: Text('Get.lazyPut Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Check console to see when controller is created'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // This will create the controller for the first time
                final controller = Get.find<CounterController>();
                controller.increment();
              },
              child: Text('Increment (creates controller)'),
            ),
            ElevatedButton(
              onPressed: () {
                final controller = Get.find<CounterController>();
                Get.snackbar('Count', '${controller.count}');
              },
              child: Text('Show Count'),
            ),
            ElevatedButton(
              onPressed: () {
                Get.delete<CounterController>();
                Get.snackbar('Deleted', 'Controller disposed');
              },
              child: Text('Delete Controller'),
            ),
          ],
        ),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 3

When does Get.lazyPut create the instance?

A
Immediately when Get.lazyPut is called
B
On first call to Get.find
C
When the app starts
D
Only if permanent is true
Q2
of 3

What does fenix: true do?

A
Makes the instance permanent
B
Allows recreation after disposal
C
Creates the instance asynchronously
D
Prevents lazy loading
Q3
of 3

Which method would you use to register a controller that may not be used at all during a session?

A
Get.put
B
Get.lazyPut
C
Get.create
D
Get.putAsync

Previous

getx put

Next

getx find

Related Content

Need help?

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