> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craftkit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Variables & loops

> How dot-path scalar keys nest, how loops bind arrays of objects, and the one binding rule that silently empties a loop if you get it wrong.

A template's manifest has two parts: **scalar variables** and **loops**. The render endpoint
builds a validator from the manifest and checks your `data` against it. Anything not in the
manifest is **stripped** before the render runs — so a key that does not bind is silently dropped,
not rejected.

## Scalar variables nest by dot-path

A scalar variable key with dots nests into an object. Declaring `customer.name` and
`customer.email` means you send:

```json theme={null}
{ "data": { "customer": { "name": "Ada", "email": "ada@example.com" } } }
```

Scalar `dataType` rules are in [Concepts](/concepts#variable). Note that `image` and `url` accept
**http(s) URLs only** — see [Images & signatures](/guides/images-and-signatures).

## Loops bind arrays of objects

A loop iterates an array of objects. Each loop declares:

<ParamField path="key" type="string" required>
  The top-level key your array is sent under. **Must be dot-free** — see the rule below.
</ParamField>

<ParamField path="label" type="string" required>
  Human-readable label.
</ParamField>

<ParamField path="itemFields" type="VariableDefinition[]" required>
  The shape of each row (at least one field). Each field is a normal typed variable.
</ParamField>

<ParamField path="previewData" type="object[]">
  Up to 10 sample rows for the builder preview.
</ParamField>

Arrays are capped at **10,000 items** per loop. You send the array at the top level of `data`,
keyed by the loop `key`:

```json theme={null}
{
  "data": {
    "areas": [
      { "areaKey": "hull", "condition": "damage", "severity": "cosmetic" },
      { "areaKey": "engine", "condition": "ok" }
    ]
  }
}
```

## The loop-key rule

<Warning>
  **A loop key must be a dot-free, top-level key.** Scalar keys nest by dot-path; **loop keys do
  not** — the validator uses a loop's `key` verbatim as a single top-level property. Declare a loop
  key with a dot and your array will never bind: it gets stripped and the loop defaults to an empty
  array, so the section renders blank with no error.
</Warning>

| Loop `key`       | Send the array as              | Result                                  |
| ---------------- | ------------------------------ | --------------------------------------- |
| `areas`          | `data.areas`                   | ✅ binds                                 |
| `lineItems`      | `data.lineItems`               | ✅ binds                                 |
| `handover.areas` | `data["handover.areas"]`       | ⚠️ binds only at the literal dotted key |
| `handover.areas` | `data.handover.areas` (nested) | ❌ stripped → empty array, blank section |

This rule applies to both the runtime validator and the JSON Schema returned by
[`GET /v1/templates/:slug`](/api-reference/get-template). **Recommendation:** give every loop a
flat, dot-free key (`areas`, `lineItems`, `passengers`) and keep your scalars under their own
namespaces (`booking.*`, `handover.*`). Mixing a `handover.*` scalar namespace with a
`handover.areas` loop is the exact shape that silently fails.

## Loops only render on the loop-capable pipeline

Declaring a loop in the manifest is necessary but not sufficient — the template must also be on a
pipeline that iterates. Document-mode templates have **no loop primitive**, so an array binds at
the API but renders nothing. Confirm the pipeline before you rely on a table:
[Render pipelines](/guides/render-pipelines).

## Arrays of primitives

There is no "array of strings" variable type. Model a list of primitives as a loop with a single
item field:

```json theme={null}
{ "key": "tags", "label": "Tags", "itemFields": [ { "key": "value", "dataType": "text" } ] }
```

```json theme={null}
{ "data": { "tags": [ { "value": "vip" }, { "value": "repeat" } ] } }
```
