Pages data sources can now bind to runtime context — URL parameters, authenticated user info, parent record fields, and static values. This means a single page definition can render different data depending on who's viewing it and how they got there.
The Problem
Before variable binding, every data source was static. A data table showed the same collection with the same filters for every visitor. If you wanted a detail page for a specific record, you had to create a separate page per record (not practical) or hardcode a filter (not dynamic).
Variable binding solves this by letting data sources reference values that are resolved at runtime.
Four Variable Sources
URL Parameters
Bind a variable to a URL query parameter. When a user navigates to /pages/customers?status=active, the status variable resolves to "active" and filters the data source.
{"variables": {"status": { "source": "url", "param": "status" }}}
This is the most common binding — it powers filtered views, detail pages (via ?recordId=...), and cross-page navigation with context.
Auth Context
Bind a variable to the authenticated user's ID, email, or name. This enables personalized views — show only records created by the current user, or filter a dashboard to the logged-in user's team.
{"variables": {"userId": { "source": "auth", "field": "userId" }}}
The publish validator warns you if you use auth-sourced variables on a public page, since unauthenticated visitors won't have auth context.
Record Context
Bind a variable to a field from the primary record on the page. This is the key to master-detail patterns — a detail page loads a customer record, and a related-list block uses the customer's ID to filter their orders.
{"variables": {"customerId": { "source": "record", "field": "customerId" }}}
Record-sourced variables are resolved in a second phase, after the primary record has been fetched.
Static Values
Bind a variable to a fixed value. Useful for setting default filters or scoping a block to a specific subset of data.
{"variables": {"status": { "source": "static", "value": "active" }}}
Two-Phase Resolution
Variable resolution happens in two phases to handle dependencies between blocks:
Phase 1 resolves blocks that don't depend on record context — URL, auth, and static variables. These can all be resolved immediately from the request context.
Phase 2 resolves blocks that depend on record context. Once the primary record block returns data from Phase 1, its fields become available for record-sourced bindings. This is what makes master-detail work: the detail block fetches the customer, then the related-list block uses the customer's fields to filter related records.
Example: Master-Detail Page
Here's a detail page that shows a customer and their related orders:
Block 1: Customer Detail (field-display, mode: single)
- Data source:
customerscollection - Variable:
idbound to URL paramrecordId - Resolved in Phase 1: fetches the customer by ID from the URL
Block 2: Related Orders (related-list, mode: list)
- Data source:
orderscollection - Variable:
customerIdbound to record fieldid - Resolved in Phase 2: filters orders where
customerIdmatches the customer record's ID
When a user navigates to /pages/customer-detail?recordId=cust-123:
- Phase 1 fetches customer
cust-123 - Phase 2 uses the customer's ID to fetch their orders
- Both blocks render with their respective data
Works With Smart Queries Too
For query data sources, resolved variables are passed directly as query parameters. If your smart query has a {{customerId}} placeholder, a variable binding fills it at runtime:
{"dataSource": {"type": "query","ref": "q-orders-by-customer","variables": {"customerId": { "source": "url", "param": "customerId" }}}}
Cross-Page Navigation
Variable binding pairs naturally with the navigate-to-page action and paramMapping. A list page can navigate to a detail page, passing the record ID as a URL parameter:
{"type": "navigate-to-page","targetRef": "customer-detail","paramMapping": {"recordId": "{{id}}"}}
The detail page picks up recordId from the URL and uses it to fetch the right record. No hardcoded IDs, no extra API calls.
Configuring in the Editor
The page editor includes a Variable Binding section on any block with a data source. Add variables, choose the source type, and configure the binding — all from the visual editor.
The publish validator catches common issues:
- Query data sources with no variable bindings declared
- Auth-sourced variables on public pages
- Record-sourced variables without a single-record block to provide context
Smart variable binding is available now in the page editor for all workspaces.