Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Use FlutterFlow Data Binding to Connect UI to Data

FlutterFlow data binding wires query results to widget properties through the Set from Variable menu. Click any widget property (text, image URL, color, visibility) and choose a source: Backend Query result, Page State, App State, Component Parameter, or Global Properties. Use Generate Dynamic Children to bind a list result to a ListView. Conditional Value creates ternary expressions for dynamic content. Data flows only downward through the widget tree to children.

What you'll learn

  • How to use the Set from Variable menu to bind any widget property to a data source
  • How Backend Query results flow through the widget tree and which widgets can access which data
  • How to use Generate Dynamic Children to render one list item per database record
  • How to create Conditional Values and Page State variables for dynamic, reactive UI
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner15 min read20-30 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

FlutterFlow data binding wires query results to widget properties through the Set from Variable menu. Click any widget property (text, image URL, color, visibility) and choose a source: Backend Query result, Page State, App State, Component Parameter, or Global Properties. Use Generate Dynamic Children to bind a list result to a ListView. Conditional Value creates ternary expressions for dynamic content. Data flows only downward through the widget tree to children.

Connect your database, API calls, and state variables to every pixel of your FlutterFlow UI

Data binding is the most important skill in FlutterFlow — it is the bridge between your database queries and your visible UI. Without it, your app displays static placeholder text no matter what is in your database. This tutorial walks through all five data binding sources in FlutterFlow: Backend Query results, Page State variables, App State variables, Component Parameters, and Global Properties. You will learn how data flows down the widget tree, why binding fails when you try to access data from the wrong scope, how to render dynamic lists, and how to use Conditional Values to change widget appearance based on data.

Prerequisites

  • A FlutterFlow project with at least one collection defined in Firestore or a Supabase table, OR an API Manager call configured
  • At least one page created with some widgets (Text, Image, ListView) that you want to bind data to
  • Test data in your database (use FlutterFlow's Content Manager to add 3-5 documents)
  • Basic familiarity with adding widgets to the FlutterFlow canvas

Step-by-step guide

1

Add a Backend Query to a page and understand data scope

Data binding begins with a data source. The most common source is a Backend Query — a database read operation attached to a widget or page. To add one: select the page (click the page name in the widget tree, not a widget on the page) → in the Properties Panel on the right, scroll to Backend Query → click Add Query. Choose Firestore (or Supabase if connected) → select your collection → set Query Type to List of Documents if you want multiple records, or Single Document for one record. Set your filters, ordering, and limit. Click Confirm. The Backend Query is now attached to the page — its result is available to every widget that is a descendant of the page in the widget tree. This is the core data scoping rule: Backend Query results flow DOWNWARD in the widget tree. A query on the page is available to all widgets on that page. A query on a Column is only available to widgets inside that Column. A query on a ListView is only available inside the ListView's child template. Understanding this hierarchy prevents the most common data binding errors.

Expected result: Backend Query appears in the Properties Panel for the page. You can see the query configuration showing the collection, filters, and ordering.

2

Bind widget properties using Set from Variable

With a Backend Query in place, you can bind any widget property to the query result. Select a Text widget on the page. In the Properties Panel → Text → click the orange lightning bolt icon (or the Set from Variable option) next to the text value. This opens the Variable Picker. Under Source, select Backend Query Record → your collection name → select the field you want (e.g., title, name, email). The text widget now displays the value of that field from the query result. The orange bolt icon appears on properties that are currently bound to a variable — static values show a plain text input. You can bind almost every widget property: Text value, Image URL (network image path), Color (using a Hex Code stored in Firestore), Visibility (a Boolean field), Width, Height, Padding. Try binding an Image widget's Network Path to a field storing an image URL — click the image widget → Network Image → Set from Variable → Backend Query → your imageUrl field. The image now loads the URL stored in your database.

Expected result: Text and Image widgets on the page display actual data from your Firestore collection instead of placeholder values.

3

Use Generate Dynamic Children to render lists from query results

When your Backend Query returns a list (Query Type: List of Documents), you need to render one child widget per item in the list. The Generate Dynamic Children feature handles this. First add a ListView widget to your page (not a Column — ListView handles scrolling and is the correct choice for database-backed lists). Select the ListView. In Properties Panel, click Generate Dynamic Children. The picker asks: what list should generate the children? Select Backend Query Result → your collection → this creates one child widget per document. Now select the auto-generated child Column inside the ListView. Inside this child Column, add a Text widget and an Image widget. When you use Set from Variable on these child widgets, the Variable Picker shows the fields for a single list item — e.g., 'Current Document in List'. Select Current Document in List → title for the Text, Current Document in List → imageUrl for the Image. FlutterFlow will render one Card per document, automatically populating each with that document's data. The ListView scrolls as needed and FlutterFlow adds pagination support through Backend Query limit and loadMore settings.

Expected result: The ListView renders one item per database document, with each item showing that document's title, image, and other bound fields.

4

Create Page State variables for temporary UI data

Page State variables store temporary data that exists only while the user is on that page — selected filter, toggle state, counter value, selected item from a list. They are not stored in the database. To add one: select the page → Properties Panel → State Variables → Add Field. Name it (e.g., selectedTab, isFilterOpen, selectedItemId) and choose a type (String, Integer, Boolean, Document Reference, etc.). Give it an initial value. Now you can bind widget properties to Page State: click a widget property → Set from Variable → Page State → your variable name. To update Page State: add an Action to a button → Update Page State → select the variable → set a new value. Example: a ChoiceChips filter widget with three options (All, Active, Inactive). On selection change → Update Page State selectedStatus = selected chip value. The Backend Query on the page has a filter: status == selectedStatus Page State variable. When the user taps a chip, the Backend Query re-runs with the new filter, and the ListView updates — all without any server-side code.

page_state_example.txt
1// Page State variables for a filtered product listing page
2// Add these in Properties Panel → State Variables:
3//
4// selectedCategory: String Initial: 'All'
5// isLoading: Boolean Initial: false
6// selectedProductId: String Initial: ''
7// sortOrder: String Initial: 'newest'
8//
9// Backend Query on the page:
10// Collection: products
11// Filter: IF selectedCategory != 'All'
12// THEN category == selectedCategory (Page State)
13// OrderBy: createdAt Descending (when sortOrder == 'newest')
14// price Ascending (when sortOrder == 'price_asc')
15// Note: use Conditional Value for dynamic orderBy:
16// if sortOrder == 'newest' → createdAt
17// else → price
18//
19// ChoiceChips binding:
20// Options: ['All', 'Electronics', 'Clothing', 'Books']
21// Initial Selected: selectedCategory (Page State)
22// On Selection Change → Update Page State selectedCategory = selectedOption

Expected result: Tapping a filter chip updates the Page State variable, triggering the Backend Query to re-run with the new filter and the ListView to refresh with filtered results.

5

Use Conditional Value and App State for advanced binding patterns

Conditional Value lets you return different data based on a condition — it is a ternary expression you build visually in FlutterFlow without writing code. Click a widget property → Set from Variable → Conditional Value. Set: if [condition] → value A, else → value B. Example: a status badge on an order card. Color: if orderStatus == 'delivered' → Color(0xFF4CAF50) green, else → Color(0xFFFF9800) orange. Text: if orderStatus == 'pending' → 'Awaiting payment', else if orderStatus == 'shipped' → 'On the way', else → 'Delivered'. App State variables work like Page State but persist across all pages and remain as long as the app is running. Add App State variables: Settings → App State → Add Field. Common uses: current user's cart items (List of JSON), notification count (Integer), selected theme (String). Bind any widget to App State the same way as Page State — Set from Variable → App State → field name. Update App State with an Action: Update App State. A common pattern: when the user adds an item to their cart on a ProductDetail page, Update App State cartCount += 1, and the cart icon in the AppBar shows a Badge bound to App State cartCount.

Expected result: Status badges show different colors based on the data value. The cart badge in the AppBar updates in real-time when items are added across different pages.

6

Bind Component Parameters to reuse components with different data

FlutterFlow Components are reusable widget groups — a ProductCard, a UserAvatar, a NotificationItem. When you create a Component and place it on multiple pages, each instance needs different data. Component Parameters let the parent pass data down to the component. To add a parameter: open the Component → Properties Panel → Parameters → Add Parameter. Name it (productName, imageUrl, price) and choose a type. Inside the component, bind the Text widget to Component Parameters → productName. Now on any page where you use this Component, you see a parameter input area in the Properties Panel: set productName = Current Document in List → title. Each instance of the component displays different data from the list. This is the correct way to build list items — create a Component with parameters, place it as the Generate Dynamic Children template, and pass list item fields as parameters. Components also accept Document Reference parameters: pass the entire document reference to the component, then inside the component run a separate Backend Query using that reference to fetch the full document.

Expected result: A single ProductCard component renders correctly across 3 different pages and in a ListView, each showing different data based on the parameters passed to it.

Complete working example

Data Binding Reference Guide
1Five Data Binding Sources in FlutterFlow
2==========================================
3
41. Backend Query Result
5 Where: attached to page, widget, or component
6 Access: only in descendant widgets (flows DOWN)
7 Picker path: Backend Query Record {collection} {field}
8 Use for: displaying database content
9
102. Page State Variables
11 Where: defined on the page, lives only during page session
12 Access: any widget on the same page
13 Picker path: Page State {variableName}
14 Update: Action Update Page State
15 Use for: selected tab, filter value, toggle state, temp counter
16
173. App State Variables
18 Where: Settings App State (global)
19 Access: any widget in any page
20 Picker path: App State {variableName}
21 Update: Action Update App State
22 Use for: cart count, notification count, user preferences, auth state
23
244. Component Parameters
25 Where: defined on Component, passed when placed on a page
26 Access: inside the component only
27 Picker path: Component Parameters {paramName}
28 Use for: reusable cards, list items, modal contents
29
305. Global Properties
31 Where: built-in, no configuration needed
32 Examples:
33 Current User uid, email, displayName, photoUrl
34 Current Time DateTime
35 Device Info platform, screen width/height, locale
36 Picker path: Global Properties {property}
37 Use for: personalization, responsive layout, time-based content
38
39Key Data Binding Patterns
40==========================
41
42List Rendering:
43 Page Backend Query (List of Documents)
44 ListView Generate Dynamic Children
45 Child Column
46 Image (Set from Variable Current Doc imageUrl)
47 Text (Set from Variable Current Doc title)
48
49Conditional Display:
50 Container Visibility
51 Conditional Value:
52 if userRole == 'admin' true
53 else false
54
55Dynamic Color:
56 Container Background Color
57 Conditional Value:
58 if status == 'active' #4CAF50 (green)
59 else #FF9800 (orange)
60
61Pass-through (page component):
62 ListView item ProductCard Component
63 productName = Current Doc title
64 price = Current Doc price
65 imageUrl = Current Doc imageUrl
66
67Scope Rule (most important):
68 Backend Query on PAGE available to ALL widgets on page
69 Backend Query on CONTAINER ONLY available inside that container
70 NEVER accessible in sibling/parent widgets

Common mistakes

Why it's a problem: Binding a widget to a Backend Query result from a query that is not its ancestor in the widget tree

How to avoid: Move the widget that needs the data INSIDE the widget that has the Backend Query, or move the Backend Query to a higher common ancestor that contains all the widgets needing the data. If both widgets are siblings, add the Backend Query to their parent Container or the page itself.

Why it's a problem: Using App State to store data that should be Page State, causing stale data from a previous page session to appear on re-visit

How to avoid: Use Page State for data that should reset when the user navigates away: selected tabs, filter values, form inputs, toggle states, error messages. Use App State only for data that intentionally persists: cart contents, notification counts, user preferences, authentication state.

Why it's a problem: Placing a Backend Query on a Text widget instead of a Container or the page, thinking it will display just that one field

How to avoid: Place the Backend Query on a Container or Column that wraps ALL the widgets needing that data. Put an Image, a Text for title, a Text for description, and a Button inside the Container. Bind each widget's properties to the Container's Backend Query result using Set from Variable.

Best practices

  • Add Backend Queries at the lowest widget level that still covers all consuming children — avoid page-level queries that fetch data for only one small section of the page
  • Use the orange lightning bolt icon as a visual signal: if it is grey, the property is static; if it is orange, it is data-bound — scan your widgets for grey bolts on properties that should be dynamic
  • Name Page State and App State variables descriptively (selectedCategoryFilter, cartItemCount) — cryptic names like var1 cause confusion when your app grows past 10 pages
  • Prefer Component Parameters over directly querying a Database in each list item — pass the data down from the parent list query rather than running N separate queries for N list items
  • Use Conditional Value for computed display properties (colors, labels, visibility) rather than adding multiple duplicate widgets with different visibility conditions
  • Test data binding in Run mode on a physical device, not just in FlutterFlow's browser preview — some binding edge cases only appear in the compiled app
  • For list items that need more data than the list query provides, use a Component with a DocumentReference parameter and a Backend Query inside the component — this is the correct pattern for detail-rich list items

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am using FlutterFlow and need to display a list of products from Firestore. Explain how to: (1) add a Backend Query to a page for a 'products' collection filtered by isActive equals true, (2) add a ListView with Generate Dynamic Children bound to the query result, (3) bind each list item's Text widget to the product title field and Image widget to the imageUrl field using Set from Variable, and (4) add a tap action to navigate to a ProductDetail page passing the product document reference as a page parameter.

FlutterFlow Prompt

Add a Backend Query to the Products page for the products Firestore collection. Filter by isActive equals true, order by createdAt descending, limit to 20. Add a ListView below the AppBar, enable Generate Dynamic Children bound to the query result, and inside the child template add an Image bound to imageUrl and a Text bound to title.

Frequently asked questions

Why is my Text widget showing an empty string even though the Firestore document has data?

Three likely causes: (1) The Backend Query is not an ancestor of the Text widget — the query is on a sibling or unrelated widget branch, so its result is not in scope. Move the Backend Query to a parent Container that wraps the Text widget. (2) The field name in the binding is misspelled or has the wrong case — Firestore field names are case-sensitive. 'Title' and 'title' are different fields. (3) The query filter is excluding the document — test the same filter in Firebase Console to confirm the document appears.

What is the difference between Page State and App State?

Page State exists only while the user is on that page — it resets to initial values every time the user navigates away and back. Use it for: selected tab, current filter, form field values, expansion state of an accordion. App State persists for the entire app session (until the app is force-closed) — it is global and accessible from any page. Use it for: cart item count, user's selected theme, notification count, anything that should survive page navigation.

How do I bind a widget to the currently logged-in user's data?

Add a Backend Query on the page with Query Type: Single Document, Collection: users, where Document ID equals Current User UID (from Global Properties → Current User → UID). This fetches the logged-in user's document. Bind widgets to this query: Text → Backend Query Record → users → displayName, Image → Backend Query Record → users → avatarUrl. Alternatively, some user fields are available directly via Global Properties → Current User without a database query: email, uid, displayName from Firebase Auth.

Can I bind a widget property to the result of a calculation?

Yes, using Custom Functions. Create a Custom Function that takes one or more input values and returns a computed result. For example, a formatPrice Custom Function that takes a Double and returns a formatted String '$29.99'. In the Set from Variable picker, select Custom Function → formatPrice → pass the price field as the argument. Custom Functions are evaluated at build time and their result can be bound to any widget property. For simpler calculations, Conditional Value supports basic comparisons without writing a Custom Function.

How do I update a specific item in a list when the user taps it?

Use the selected item's Document Reference. When the user taps a list item, store the tapped item's document reference in a Page State variable (type: DocumentReference). Add an Update Document Action to write the new value to Firestore using that reference. The real-time Backend Query on the page automatically refreshes when Firestore data changes, so the updated item appears immediately in the list without a page reload.

Why does Generate Dynamic Children show the same data in every list item?

This happens when the child widget is bound to the parent page's Backend Query instead of 'Current Document in List'. Inside the Generate Dynamic Children template, the Variable Picker should show 'Current Document in List' as a source — this represents the single current item being rendered, not the full list. If you accidentally bound to the page-level query (which returns the full result or first document), all list items show identical data. Re-open Set from Variable on each child widget and select Current Document in List → field name.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.