Unify Logo Footer.svg
Unify Applications
Logo
Data Sources Overview

Data Sources Overview

Logo

7 mins READ

Data Sources Overview

A data source is a named, reusable request for data that lives on a page or on the whole app. Configure it once — which API to call, which records to query, with what inputs — and every block on that page can bind to its results. The data source owns the fetching: when it runs, when it re-runs, how its response is shaped, and what loading and error states it exposes while doing so.

Note: Open the Data panel in the Application Builder. Data sources are grouped under App Data (shared across all pages) and Page Data (specific to this page). Variables and functions live alongside data sources but are separate concepts.

The Two Kinds of Data Sources

Every data source is one of two kinds, chosen at creation time. The kind is fixed — you cannot switch between them without recreating the data source.

KindWhat it doesTypical use
API EndpointCalls an HTTP endpoint — you configure the method, URL, query parameters, headers, and body.Reaching your own or a third-party REST API.
Platform QueryQueries data managed by the platform — you pick an operation, the fields to return, filters, sorting, and paging.Reading records the platform already stores, without writing an API.

See Data Source Types for an in-depth comparison and guidance on when to pick which.

Page Scope vs App Scope

When you create a data source you choose where it lives:

ScopeLives inAccessible fromUse when
Page DataThis page onlyBlocks on this pageThe query is specific to this page's concern
App DataThe app's global scopeEvery page in the appThe same data is needed across multiple pages — create once, use everywhere

Warning: A single page caps at 100 data sources. Hitting that limit shows a "Data source limit reached" dialog. The recommended fix is to split heavy pages, share data via App Data, or combine related queries where possible.

The Lifecycle: Configure → Run → Bind → Refresh

Every data source moves through the same four stages regardless of kind or scope.

  1. Configure: Define what to fetch: the endpoint or query, its inputs, and its run behavior. Inputs can be static values or expressions bound to page state, other data sources, or user input. Inputs configured as expressions make the data source reactive — it re-runs automatically when the referenced value changes.

  2. Run: The data source executes. An automatic data source runs on its own — on page load and again whenever an input it depends on changes. A manual one runs only when something explicitly triggers it, such as a button action.

  3. Bind Results: Blocks read the response through the data source's name in a {{ }} expression. Alongside the response data, each data source exposes its live request state:

  4. Refresh: Data stays current through three mechanisms: polling (re-run on an interval), focus refetch (re-run when the user returns to the tab), or an explicit trigger from an action. See Caching & Refetch.

Optional Lifecycle Capabilities

Two optional features extend the standard lifecycle:

CapabilityWhat it doesSee
Response TransformA JavaScript snippet that reshapes the raw response before blocks read it — flatten nesting, rename fields, compute derived values.Response Transforms
Infinite LoadingTurns the response from a fixed window into an append-only list; consuming blocks pull additional pages on demand.Infinite Loading

How to Add a Data Source

  1. Open the Data panel: In the Application Builder left rail, select the Data panel.

  2. Click + → Data Source: A searchable grid of every available app, connector (Storage, REST/HTTP, GraphQL, automations) appears.

  3. Pick the app and operation: Select the app, choose its operation. The data source is created and opens its configuration with four tabs: Apps, Connection, Input, and Advanced.

  4. Configure inputs, run behavior, and advanced options: On the Input tab set run behavior (Automatic / Manual), configure the operation's inputs, and optionally add a response transform or event handlers. The Advanced tab controls caching, polling, retry, and disable conditions.

  5. Save and Run: Click Save and Run (or Run / Preview) to test the data source and inspect its output shape.

Binding to a Data Source

Example — Binding a table to a data source result

Assuming a data source named orders_query that returns a list of orders:

// Bind the Table's data property to all records {{ orders_query.data.objects }} // Show a loading spinner conditionally {{ orders_query.isLoading }} // Show the error message when the query fails {{ orders_query.error.message }} // Count results {{ (orders_query.data.objects || []).length }}

Success & Failure Events

After a run finishes, the data source fires its On Success or On Failure event. These are ordinary action lists where you chain toasts, navigation, or further actions off the fetch outcome. Attach them on the Input tab under Event Handlers.

Tip: Put "what happens after a save" logic (show a success toast, navigate back) in the data source's On Success event — not chained inline after a trigger action — so it only runs when the fetch actually succeeded.

Common Gotchas

GotchaExplanation
Automatic is not "always fresh"An automatic data source re-runs when its bound inputs change — not when the server's data changes. Use polling or an explicit refresh to pick up server-side changes.
Manual data shows nothing until triggeredA block bound to a manual data source shows nothing until something fires it. Bindings resolve to empty values before the first run.
Legacy mode is automatic-like but differentData sources created before run behavior existed have no mode set. The platform treats them like automatic sources, but triggering them from an action differs slightly. Set an explicit mode to remove ambiguity.
Automatic can mean many runsEvery distinct change to a bound input triggers a re-run. An input bound to rapidly changing values (unthrottled typing) re-fetches on each keystroke. Prefer binding to settled values or use manual run behavior.
  • Data Source Types — API endpoint vs platform query: what each configures and when to choose which.

  • Query Builder — Building a platform query: operations, returned fields, filters, sorting, and paging.

  • Run Behavior & Triggering — Automatic vs manual, page-load behavior, dependency ordering, triggering from actions.

  • Caching & Refetch — Polling, background and focus refetch, retries, and action-driven refreshes.

  • Response Transforms — Reshaping a response with JavaScript before blocks read it.

  • Infinite Loading — "Load more" pagination — the has-more flag, the cursor, and how blocks consume pages.

  • Data Binding — The {{ }} expression syntax that connects data source results to UI blocks.

Frequently Asked Questions

What is the difference between App Data and Page Data?

App Data sources are created once and available across every page in the app — useful for things like the current user's profile or global configuration that many pages need. Page Data sources belong to a single page and are not accessible from other pages. If you find yourself duplicating the same data source on multiple pages, move it to App Data instead.

Why does my data source show nothing on the initial page load?

The most common cause is that the data source is set to Manual run behavior. Manual sources only run when explicitly triggered — they show empty values until something fires them. Check the data source's Input tab: if Run Behaviour is Manual and you want data to appear on load, either switch it to Automatic or enable Run query on page load in the Advanced tab.

Can I use the same data source on multiple blocks on the same page?

Yes — any block on the page can bind to any data source by name. The data source runs once and all consuming blocks share the same result. You do not need to create separate data sources for each block.

What happens to the page if a data source fails?

The data source transitions to an error state — error becomes non-null and isLoading / isFetching become false. Blocks bound to data continue showing whatever they had before (or nothing, on first load). The failure events fire, which is where you can show an error message or take corrective action. The page itself does not crash.

How do I refresh a list after saving or deleting a record?

Use the Trigger Data Source action in the save/delete operation's On Success event handler. Point it at the list's data source — this invalidates the cached result and re-fetches, updating the list to reflect the change. Place the trigger in the save data source's On Success event so it only fires after a confirmed successful save.