Backend Query
Backend Query helps you to trigger a query automatically whenever a user navigates to the page containing the query. You can set a Backend Query on a particular widget or an entire page. The information retrieved using the Backend Query can be used in any widget present inside.
FlutterFlow provides the following types of Backend Queries that you can specify on any widget or page of your app (you can navigate to the specific Backend Query page to learn how to use it):
The difference between an Action and a Backend Query:
Action requires the user to perform a gesture like a tap or a double-tap on the widget containing the Action. You can specify more than one Action on the same widget.
Backend Query gets triggered automatically as soon as the user navigates to the page containing the query. You can specify only one Backend Query on a particular widget or page.
While the backend query is busy retrieving results, it shows the default Project Theme Loading Indicator (which you can change from Settings and Integrations > General > Theme > Loading Indicator). However, if you want to replace this with a custom loading indicator, such as a GIF image, follow the instructions below:

Custom loading indicator
To change the loading indicator:
- 1.Ensure you have added a backend query.
- 2.Open the Backend Query section (on the right side) and scroll down to the Backend Query Loading Widget. Open it by clicking on the arrow icon.
- 3.Set the Loading Widget Type to Image. You can also choose a Component if you have already designed a loading component.
- 4.Enable the View in UI Builder. This allows you to see your custom loading indicator on canvas (before you actually run the app).
- 5.
- 6.To show the indicator in the center, turn on the Center Image toggle.
- 7.Run the app, and your custom loading indicator will appear while the data is being loaded.

Changing loading indicator
Sometimes you might want to display the same list of items with a little modification. For example, showing all Todo items and completed Todo items. In such a case, you can copy-paste the entire backend query to speed up the building process. This is helpful, especially when you have a complex backend query.
To copy-paste the query:
- 1.Select the widget (e.g., ListView, GridView, etc.) where you have already added the backend query.
- 2.Select the Backend Query tab, scroll down and click the Copy button.
- 3.Now, select the widget (where you want to add the query), move to the Backend Query tab click the Paste Backend Query button.
- 4.Click Confirm.

Copy-paste backend query
The Empty List widget is a widget used to display a message when there are no items in a list. It is typically used in cases where a list view is empty, to display a message to the user indicating that there is no data to display. This widget helps to provide a better user experience by displaying a message instead of just an empty screen.
To display the empty list widget:
- 2.Select the scrollable widget (on which you have added the backend query), move to the properties panel, and turn on the Show Empty List Widget.
- 3.Set Widget Type, to Image or Component. The further options are available based on what you choose.
- 4.Try toggling the View in UI Builder. This allows you to see your empty list widget on canvas (before you actually run the app).
- 5.You can also control the size and centering of the widget using the available options.

Enabling the empty list widget
Backend query caching refers to the process of storing the result of a backend query in a cache so that subsequent queries for the same data can be served directly from the cache rather than making a new query to the backend.
Caching a query can bring significant benefits to your app, including improved performance and reduced server load. Additionally, caching can enable your app to function offline by serving cached results when there is no internet connection available.
For example, an e-commerce app can cache product data, such as product descriptions, prices, and images, to avoid making unnecessary API calls for each page load.
For Firebase queries, you must enable Single Time Query; otherwise, the query is considered as real-time, and the changes will be reflected as soon as the data is updated.
In general, any data that is static, slowly changing, or read more often than they are updated can be cached to improve performance and reduce the load on the server. A few examples are
- 1.Static content such as images and videos.
- 2.Configuration data such as application settings or system parameters.
- 3.Data that is expensive to compute, such as complex reports or analytics.
Sometimes, it's not a good idea to cache the backend query. Here are some examples:
- 1.Large amounts of data can cause performance issues and may not be appropriate.
- 2.Sensitive or confidential data should not be cached, as it could lead to unauthorized access.
- 3.Frequently changing data, such as in real-time or near real-time scenarios, caching may not be appropriate as the cached data could quickly become stale or outdated.
- 4.Critical response time where the data needs to be up-to-date and accurate at all times.
Let's see how to cache a backend query with an example app that shows a list of employees on the first page and employees' details on the second page. On the employee details page, the data is retrieved from a backend query and read more often than they are updated so it's a good candidate to cache.
To improve performance, you can cache the data on the details page so that it can be quickly retrieved and displayed to users.
Here is how it looks:

Caching backend query
In the visual above, see how the loading indicator appears for the first time a query is made on the page. However, subsequent queries will retrieve the result from the cache, and the loading indicator will not be displayed again.
To cache the backend query:
- 1.Ensure you have added a backend query. For this example, to retrieve data from a Firebase document, we add a backend query at the page level as Single Time Query. We use a document reference to get the employee details.

Querying employee details using document reference
- 2.Open Query Cache Settings and Enable Query Caching.
- 3.Determine the Scope of the cache. If you set it to App Level and the exact same query is made on any other page of the app, it will display the result from the cache. However, if you set the Page Level, the cached result will be used only on that page if the query is made multiple times on the same page.
- 4.If the current query is completely new/different, create a Query Name. If not, and you want to use the cached result of this query (that might be created somewhere else), select the name from the list.

Enabling query caching
- 5.If we leave this example here, we'll have data inaccuracy issues. That means when any employee data is cached, the same data will be used for all employees, which is not what we want. We want to cache data for all individual employees. To do so, we can set the Unique Key. Here the unique key can be the employee id or the document reference.

Adding Unique Key

Data inaccuracy issue without Unique Key (click to enlarge)
- 6.At this point, we have enabled the caching, but we still have one problem. Once the query is cached, it will be used forever, although we update the data in our backend. This is because we are not clearing or invalidating the cache at the appropriate time. To properly invalidate the cache, you can use the Should Override Cache property OR Clear Query Cache action. This helps you remove the cached data that has become stale or outdated.
- 1.The Should Override Cache property accepts a boolean (True/False). That means we can provide a variable (e.g., an App State variable named isCacheOverride) that knows when to override the cache. So create one and set it here.
- 2.Create one more App State variable, something like lastCacheTime, and set the current time as default. This will be used to save the time of results retrieved from the backend. You'll better understand how helpful it is in the logic we add in the next step.

App State variables

Setting Should Override Cache to App State variable
- 7.Now we must add a logic that determines whether to override cache (every time when the page is loaded) and set the isCacheOverride variable accordingly. Here is how it goes:
- 1.First, check if the lastCacheTime is set or not. If not, set the current time to it.
- 2.Then the idea is to create one custom action that checks if the current time is more than 30 minutes ahead of the lastCacheTime. Note that 30 minutes is the cache expiration time, and here it is kept minimum just for simplification purposes, it's important to carefully choose the appropriate expiration time for your cache based on the nature of your data.
- 3.if True :
- 1.Update the lastCacheTime with the current time and isCacheOverride to True. Make sure you keep the Update Type to Rebuild Current Page so that the backend query is made again, which will invalidate the cache and display updated data.
- 2.
- 3.Continuing the same action flow, wait for 1 sec and again update isCacheOverride to False so that the cached result won't override on page load for the next 30 min.

Cache clear logic
Note that in this example, we use both the Clear Query Cache action and the Should Override Cache property to clear or invalidate the cache. Although both perform the same task, it's generally considered better practice to explicitly Clear Query Cache rather than relying on the Should Override Cache bool. However, in certain cases, you may want to override the cache conditionally instead of with an explicit action, so the option is there.
Here is how the custom function looks in case you want to check:
bool isOverrideCacheAction(DateTime cacheTime) {
// Add your function code here!
return DateTime.now().difference(cacheTime).inMinutes > 30;
}

Custom function to know if last cache time is more than 30 minutes
Tip: You can have a separate lastCacheTime variable for all the employee records to avoid any conflict with others. Failing to do so may keep on updating the common lastCacheTime variable, and you might not see updated data. For example, creating a list of JSON that contains the id and lastCacheTime of an employee might help. Like this:
{ "id": 1, "lastCacheTime": '2023-03-22T14:30:00+00:00', }
Last modified 2mo ago