Infinite Loading
Infinite loading turns a data source's response from one fixed window into an append-only list: the first run fetches a page, and consuming blocks can keep asking for the next page — on scroll or a "Load More" control — with each new page added below the ones already shown. The user sees one continuously growing list; behind it the data source issues one request per page.
Which Data Sources Load Infinitely
Infinite loading is not a toggle you flip — it activates automatically for platform operations that return lists the platform knows how to page.
| Operation type | Infinite loading | Note |
Platform query — multiple records (numberOfRecordsToFetch: MULTIPLE) | Yes | Switching to SINGLE makes it a plain one-fetch source. |
| Audit queries | Yes | Always infinite. |
| Standard entity fetches | Yes | Always infinite. |
| Analytics query reports | Yes | Always infinite. |
| Callable automations (list-returning) | Yes | Always infinite. |
| API endpoint or single-record platform query | No | Returns one response. Use offset/limit in the query to page by replacement. |
How Paging is Wired
An infinite data source's pagination is described by a handful of internal paths that tell the platform where paging information lives in the request and response.
| Paging signal | Default path | Description |
| Items array | objects | The path in the response holding the actual items to append. |
| Page size | 20 | Records per page. Configured via the request's limit input. |
| Offset | 0 | Starting position. Advances by page size after each fetch. |
| Paging strategy | Offset-based | Default is offset (count-based). Some operations support cursor-based paging — the platform follows the response's cursor instead of counting items. |
| Has-more signal | hasMore | A boolean flag in the response. When present, this is the definitive signal for whether more pages exist. |
| Total count | — | Fallback when no has-more flag: the platform compares total count against records fetched so far. |
Has-Next-Page Decision Logic
The "is there more?" decision follows a strict precedence:
Has-more flag — if a boolean
hasMorepath is configured and the response provides it, this wins.Total count — fallback: more pages exist while the total count exceeds what's been fetched so far.
Neither available — loading stops after the current page with no error. The list simply never grows.
What Consuming Blocks See
Blocks bound to an infinite data source read one combined response, not a stack of pages.
| Exposed state key | Description |
| data.objects | Every fetched page's items combined into one flat array, in order. New items append as pages load. |
| isLoading | True during the very first page fetch. |
| isFetching | True during any fetch — first page or subsequent pages. |
| isFetchingNextPage | True specifically while a next-page fetch is in flight. Use this to show a "loading more" indicator without hiding the already-loaded items. |
| hasNextPage | True while more pages exist. Use to conditionally show/hide a "Load More" button or end-of-list message. |
| error | Present when the last page fetch failed. |
Note: Table, Timeline, and similar list-style blocks that consume data sources request the next page themselves when the user reaches the end. You do not need to wire a "fetch next page" action manually for scroll-based pagination in these blocks.
Binding Example
Example — Binding an infinite data source to a repeatable list
// Data source: orders_list (infinite, returns multiple records) // Repeatable's content property: {{ orders_list.data.objects }} // Show a loading-more indicator: {{ orders_list.isFetchingNextPage }} // Show "Load More" button only when more exist: visibility: {{ orders_list.hasNextPage }} // Show end-of-list message when done: visibility: {{ !orders_list.hasNextPage && !orders_list.isLoading }}
When Inputs Change
Changing a bound input (filter, sort, search) starts the list over: the new inputs define a new result set, so paging restarts from the first page rather than appending mismatched results. The previously loaded list stays visible while the fresh first page loads — the block doesn't blank out during the switch.
Tip: You don't need to manually reset pagination state when a filter changes. The infinite data source detects the input change and automatically resets to page 1 on the next render cycle.
Transforms and Infinite Loading
A response transform on an infinite data source runs per page. The transformed pages' item lists are combined — but the has-more flag and total count are read from the transformed response, not the raw one. If your transform returns only the items array and discards the paging signals, "Load More" silently stops after the first page.
Warning: When using a transform on an infinite data source, preserve the hasMore flag (and/or total count) in whatever shape your transform returns. Dropping them causes the first page to look like the last.
Offset Paging vs Infinite Loading
| Behavior | Offset paging | Infinite loading |
| New pages replace or append? | Replace — shows a different window | Append — grows the list downward |
| How configured | Limit + offset inputs in the Query Builder | Automatic for supported operation types |
| Scroll-to-load behavior | Not automatic — requires action wiring | Built in to list-style blocks |
| Binding path | {{ ds.data.objects }} (one page at a time) | {{ ds.data.objects }} (all loaded pages combined) |
Gotchas
| Gotcha | Details |
| No paging signal = one page, silently | If the response exposes neither a has-more flag nor a usable numeric total, loading ends after the first page with no error — the list just never grows. |
| A transform that drops paging signals | Returning only the items array from a transform strips the has-more flag. "Load More" stops after page 1 with no error or warning. |
| Non-list fields show the latest page only | Any per-page metadata (such as a page-scoped count) reflects the last fetch, not the accumulated total. Binding a "total shown" label to such a field will look wrong after page two. |
| Not a toggle | You cannot independently turn infinite loading on or off for an arbitrary data source. It is determined by the operation type. To get a plain one-fetch source, change the operation to return a single record. |
Frequently Asked Questions
How do I know if my data source supports infinite loading?
Infinite loading activates automatically for platform operations that return lists the platform can page: entity record fetches (configured for multiple records), audit queries, analytics reports, and callable automations. You cannot turn it on or off independently — it is determined by the operation type. If a data source returns a single response with no paging signals, it is not an infinite source.
My "Load More" button stops working after the first page. What's wrong?
The most likely cause is a response transform that returns only the items array, dropping the hasMore flag or total count that tells the platform there are more pages. Check your transform code and ensure it returns the full page object, including the paging signals. Without those signals, the platform assumes the first page is the last.
Does changing a filter reset the pagination back to page 1?
Yes — when any bound input (filter, sort, search) changes, the infinite data source automatically restarts from page 1. The new inputs define a new result set, so pages from the old set would be mismatched. The previously loaded items stay visible while the fresh first page loads, so the block doesn't flash empty during the transition.
How do I show an end-of-list message when all records have loaded?
Bind a block's visibility to {{ !my_datasource.hasNextPage && !my_datasource.isLoading }}. When hasNextPage is false and the source is not loading, all pages have been fetched. You can pair this with isFetchingNextPage to show a "loading more" indicator while intermediate pages are in flight.