flutter
/

GetX Permanent Controller: Keep Controllers Alive Forever

Last Sync: Today

On this page

11
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

GetX Permanent Controller: Keep Controllers Alive Forever

What is a Permanent Controller?

By default, GetX automatically disposes controllers when they are no longer in use (e.g., when a route is popped). A permanent controller is one that never gets disposed automatically. It lives for the entire lifetime of the app, making it ideal for global services like authentication, theme management, API clients, or any shared state that must persist across routes.

Creating a Permanent Controller

To make a controller permanent, set permanent: true when registering it with Get.put or Get.lazyPut.

DARTRead-only
1
// Using Get.put
Get.put(AuthController(), permanent: true);

// Using Get.lazyPut
Get.lazyPut(() => AuthController(), permanent: true);

You can also use GetxService, which is a convenience class that is already permanent by default.

DARTRead-only
1
class AuthService extends GetxService {
  // This service is automatically permanent
}

// Register
Get.put(AuthService()); // or Get.lazyPut(() => AuthService());

Permanent vs Non-Permanent

When to Use Permanent Controllers

  • Authentication state – User login status should survive across screens.
  • Theme / settings – App-wide preferences that should persist.
  • API services – Dio client, database connections, etc.
  • Notification handlers – Services that listen for push notifications.
  • Analytics – Track user sessions across the whole app.

Lifecycle of a Permanent Controller

A permanent controller is created once (when first registered or accessed, if lazy) and never disposed unless you manually call Get.delete. Its onInit() is called once, and onClose() is called only when you delete it manually.

DARTRead-only
1
class PermanentController extends GetxController {
  @override
  void onInit() {
    super.onInit();
    print('Initialized once');
  }

  @override
  void onClose() {
    print('Closed only when manually deleted');
    super.onClose();
  }
}

// Later, to delete:
Get.delete<PermanentController>();

Permanent Controllers in Bindings

You can register permanent controllers in bindings. They will be created when the route is first opened and remain alive even after the route is closed.

DARTRead-only
1
class AppBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => AuthService(), permanent: true);
    Get.lazyPut(() => ApiClient(), permanent: true);
  }
}

GetMaterialApp(
  initialBinding: AppBinding(),
  // ...
);

Accessing Permanent Controllers Anywhere

Because they are permanent, you can access them from any controller, widget, or service using Get.find<MyController>() at any time.

DARTRead-only
1
// In any widget or controller
final auth = Get.find<AuthService>();
if (auth.isLoggedIn.value) { ... }

Best Practices

  • Use GetxService for app-wide services – It clearly communicates intent and is permanent by default.
  • Limit permanent controllers – Only for truly global dependencies. Overusing them can lead to memory bloat.
  • Dispose resources manually when needed – If your permanent controller holds streams or timers, close them in onClose (which you may call manually when the app terminates).
  • Avoid holding large data in permanent controllers – Prefer caching strategies that can be cleared.
  • Test with Get.reset() – In unit tests, reset the dependency container to avoid state leakage.

Common Mistakes

  • ❌ Making every controller permanent – Unnecessary memory usage. ✅ Use permanent only for global services.
  • ❌ Not cleaning up resources – Even permanent controllers should close streams in onClose if they are ever deleted manually. ✅ Override onClose and dispose resources.
  • ❌ Registering a permanent controller inside a widget's build – Causes re‑registration and potential leaks. ✅ Use bindings or initState.
  • ❌ Assuming permanent controllers are automatically disposed – They are not; you must call Get.delete if you ever need to remove them.

FAQ

  • Q: What's the difference between permanent: true and GetxService?
    A: GetxService is a convenience class that already has permanent: true set. It's the recommended way for app‑wide services, but both work identically.
  • Q: Can I make a permanent controller lazy?
    A: Yes, use Get.lazyPut(() => MyController(), permanent: true). It will be created on first access and never disposed.
  • Q: How do I manually delete a permanent controller?
    A: Call Get.delete<MyController>(). This will call onClose() and remove it from the registry.
  • Q: Will a permanent controller survive a hot restart?
    A: Hot restart re‑runs main(), so all controllers are re‑initialized. They will be recreated.
  • Q: Should I use permanent for a controller that holds a WebSocket connection?
    A: Yes, that's a good use case. But remember to close the connection in onClose if you ever delete the controller (or in a close method).

Conclusion

Permanent controllers are a powerful feature in GetX that let you create global, long‑lived dependencies. By using permanent: true or GetxService, you can manage app‑wide state and services with ease. However, use them judiciously to keep your app memory‑efficient.

Try it yourself

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

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

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

  @override
  void onInit() {
    super.onInit();
    print('Permanent controller created');
  }

  @override
  void onClose() {
    print('Permanent controller closed (only on manual delete)');
    super.onClose();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Register permanent controller
    Get.put(PermanentCounter(), permanent: true);
    return GetMaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  final counter = Get.find<PermanentCounter>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Permanent Controller')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Obx(() => Text('Count: ${counter.count}', style: TextStyle(fontSize: 32))),
            ElevatedButton(
              onPressed: counter.increment,
              child: Text('Increment'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => Get.to(SecondPage()),
              child: Text('Go to Second Page'),
            ),
          ],
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  final counter = Get.find<PermanentCounter>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second Page')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Obx(() => Text('Count: ${counter.count}', style: TextStyle(fontSize: 32))),
            ElevatedButton(
              onPressed: counter.increment,
              child: Text('Increment'),
            ),
            ElevatedButton(
              onPressed: () => Get.back(),
              child: Text('Back'),
            ),
          ],
        ),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 3

How do you make a controller permanent when using Get.put?

A
Get.put(MyController(), keepAlive: true)
B
Get.put(MyController(), permanent: true)
C
Get.putPermanent(MyController())
D
MyController().permanent()
Q2
of 3

What happens to a permanent controller when a route that uses it is popped?

A
It is automatically disposed
B
It stays alive
C
It is recreated
D
It throws an error
Q3
of 3

Which class is a permanent controller by default?

A
GetxController
B
GetxService
C
Obx
D
GetView

Previous

getx smart management

Next

getx authentication flow

Related Content

Need help?

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