Flutter Query

Flutter Query

Garbage Collection

How Flutter Query removes unused cache entries to free memory

What is garbage collection?

Garbage collection removes cached data that is no longer being used. When all widgets observing a query unmount, that cached data becomes "inactive." After a period of inactivity, the cache entry is removed to free memory.

The garbage collection duration (gcDuration) controls how long inactive cache entries remain in memory before being removed. By default, this is 5 minutes.

Why garbage collection matters

Without garbage collection, your app's memory usage would grow indefinitely. Every query your user visits would remain cached forever, even for screens they'll never return to.

But removing cache entries immediately would defeat the purpose of caching. If a user navigates away from a screen and back within seconds, they'd have to wait for a fresh network request instead of seeing cached data instantly.

Garbage collection provides a balance: keep data around long enough to benefit from caching, but not so long that memory becomes a problem.

The lifecycle of a cache entry

Consider what happens when you use a query:

Widget mounts

A widget subscribes to a query with key ['todos'].

Data fetched and cached

The query fetches data from the server and stores it in the cache.

Widget unmounts

The user navigates away. No other widgets are observing the query.

GC timer starts

The garbage collection timer begins counting down (5 minutes by default).

Cache entry removed

The cache entry is removed after the set garbage collection duration.

If another widget subscribes to ['todos'] before the timer expires, the cached data is immediately available. The timer is cancelled, and the cycle restarts when that widget unmounts.

Configuring garbage collection duration

The gcDuration parameter controls how long inactive cache entries persist. By default, this is 5 minutes:

final result = useQuery(
  const ['todos'],
  (context) async => await fetchTodos(),
  gcDuration: const GcDuration(minutes: 30), 
);

The GcDuration constructor accepts the same named parameters as Dart's Duration:

const GcDuration(minutes: 5)
const GcDuration(seconds: 30)
const GcDuration(hours: 1)
const GcDuration(days: 1, hours: 12)

GcDuration also provides two predefined constants:

  • GcDuration.infinity: The cache entry is never garbage collected. Use this for data that should persist for the entire app session, like user profile information or app configuration.
  • GcDuration.zero: The cache entry is removed immediately when the last observer unmounts. Use this for sensitive data that shouldn't linger in memory, or for large data structures you want to discard quickly.

When garbage collection runs

The garbage collection timer starts when the last widget observing a query unmounts and the query is idle (not fetching). By default, the timer is set to 5 minutes. If a fetch is in progress, the timer waits until it completes. This avoids removing a query mid-fetch and wasting the in-flight network request.

When a new widget subscribes before the garbage collection timer expires, the timer is cancelled. The cached data remains available, and the cycle restarts when that widget unmounts.

Multiple observers with different durations

When multiple widgets observe the same query with different gcDuration values, the query uses the longest duration. This ensures no widget's cache preferences are overridden by a more aggressive setting elsewhere.

For example, if Widget A specifies 5 minutes and Widget B specifies 30 minutes, the cache entry will persist for 30 minutes after both widgets unmount.

Garbage collection vs staleness

Garbage collection and staleness are related but distinct concepts:

AspectStaleness (staleDuration)Garbage Collection (gcDuration)
Question answeredShould I refetch?Should I keep this in memory?
When checkedOn mount, on resumeWhen last observer unmounts
Effect when triggeredBackground refetch startsCache entry removed
Data availabilityData still availableData gone

A query can be stale but still cached. A stale query returns its cached data immediately while refetching in the background. A garbage-collected query has no cached data at all—the next mount starts fresh with a loading state.

The common configuration is a short staleDuration (or the default of zero) with a longer gcDuration. This means data is refetched frequently to stay current, but remains cached for quick access during navigation.

On this page