← Back to all posts
4 min readCentrali Team

Smart Variable Binding: Dynamic Pages That Respond to Context

Bind URL parameters, auth context, record fields, and static values to block data sources — enabling master-detail patterns, filtered views, and personalized pages without writing code.

FeatureProductTutorial

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.

```json { "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.

```json { "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.

```json { "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.

```json { "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: `customers` collection
  • Variable: `id` bound to URL param `recordId`
  • Resolved in Phase 1: fetches the customer by ID from the URL

Block 2: Related Orders (related-list, mode: list)

  • Data source: `orders` collection
  • Variable: `customerId` bound to record field `id`
  • Resolved in Phase 2: filters orders where `customerId` matches the customer record's ID

When a user navigates to `/pages/customer-detail?recordId=cust-123`:

  1. Phase 1 fetches customer `cust-123`
  2. Phase 2 uses the customer's ID to fetch their orders
  3. 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:

```json { "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:

```json { "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.

Building something with Centrali and want to share feedback about this feature?

Email feedback@centrali.io