---
title: "Dynamic sources"
description: "Bind component settings and repeaters to Shopify route and commerce data."
canonical_url: "https://nyxel.dev/docs/dynamic-sources"
markdown_url: "https://nyxel.dev/docs/dynamic-sources.md"
---

# Dynamic sources
URL: /docs/dynamic-sources
LLM index: /llms.txt
Description: Bind component settings and repeaters to Shopify route and commerce data.

# Dynamic sources

A dynamic source connects a component setting to data already available for the active storefront route. It lets one template describe many products, collections, pages, or articles without copying resource values into template JSON.

![Nyxel collection route showing products supplied by collection data, with filtering and sorting.](/site-media/storefront-collection.png)

## Static values and bindings

A setting usually resolves from either a stored value or a binding:

```json
{
	"heading": "Featured products",
	"image": {
		"binding": {
			"scope": "product",
			"path": "featuredImage"
		}
	}
}
```

The first value is authored directly. The second reads `featuredImage` from the product in the current source frame. The component receives both as ordinary resolved values; it does not need to know which one came from a binding.

The Inspector shows a source picker only when a setting and source value are compatible. Text settings can bind to textual fields, media settings to images, resource settings to matching Shopify resources, and list-capable settings to lists.

## Source scopes

The route loader creates a source context for the page. Common scopes include `product`, `collection`, `page`, `blog`, `article`, `cart`, and `shop`. A repeater adds a local frame for each item, which makes scopes such as `closest:product` or `closest:line` available to descendants.

Use the narrowest meaningful scope. A product card inside a collection loop should bind to `closest:product`; a product-page hero can bind to the route-level `product`. This keeps the component reusable when it moves into another composition.

## Lists and repeaters

The `loop` block reads a list source and renders its child region once per item. Each iteration creates a new source frame, so nested blocks can bind to the active item without receiving manually threaded props.

A collection grid commonly uses this shape:

```json
{
	"type": "loop",
	"settings": {
		"iteration_source": {
			"binding": { "scope": "collectionPage", "path": "products" }
		},
		"page_size": 24
	},
	"regions": {
		"default": [
			{
				"type": "product-card",
				"settings": {
					"product_ref": {
						"binding": { "scope": "closest:product", "path": "" }
					}
				}
			}
		]
	}
}
```

The collection route remains responsible for pagination, filters, sorting, locale, and market. The loop is responsible for presentation of the supplied list.

## Resolution rules

Resolution is deterministic. The runtime validates the binding shape, locates its scope, walks the path, coerces the result according to the setting definition, and falls back to the contract default when the value is missing or incompatible.

Canvas receives serialized source data in its render request. Preview and public routes build request-scoped sources through Astro middleware and route loaders. Components therefore use the same binding semantics in all three surfaces.

## Resource pickers

Resource pickers store a Shopify reference when an author chooses a specific item. Starter templates should stay store-independent. When a preset needs representative route data, bind to a route scope or a built-in default resource rather than embedding a `gid://shopify/...` value.

Metaobjects and metafields can participate in the same model as their query and editor support expands. See [Content models](/docs/content-models) for the ownership boundary.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
