---
source: https://carbone.io/documentation/design/repetitions/with-arrays.html
title: "Repeat any part of your document with a loop on arrays"
description: "Repeat any part of your document"
generated_at: "2026-07-24"
---

# Loop over array

Repeat any part of your document  
COMMUNITY FEATURE Available for:  
✓ Carbone Cloud  
✓ Carbone On-premise  
✓ Embedded Carbone JS   v2.0+ 

## Overview

Carbone repeats any part of a document (rows, titles, pages...) from an array in your data.

Mark the pattern with two consecutive items: `[i]` on the first, `[i+1]` on the next. Carbone takes the `[i]` item as the example, automatically detects the block to repeat, outputs one copy per array element, and removes the `[i+1]` marker row before rendering.

> ℹ️ **Note:** An empty array renders nothing: both the `[i]` and `[i+1]` rows are removed.

## Simple array

In this example, we want to loop over an array of cars. This is a **vertical loop**: Carbone repeats the pattern **downward**, adding one row per array item.

```cdata
{
  "cars" : [
    {"brand" : "Toyota" , "id" : 1 },
    {"brand" : "Hyundai", "id" : 2 },
    {"brand" : "BMW"    , "id" : 3 },
    {"brand" : "Peugeot", "id" : 4 }
  ]
}
```

**Template:**

| Cars | id |
| --- | --- |
| {d.cars[i].brand} | {d.cars[i].id} |
| {d.cars[i+1].brand} |   |

**Result:**

| Cars | id |
| --- | --- |
| Toyota | 1 |
| Hyundai | 2 |
| BMW | 3 |
| Peugeot | 4 |

> ℹ️ **Note:** Only one `[i+1]` tag is enough to find the repetition pattern. It is not necessary to repeat the whole `[i+1]` part.

Get inspired by one of our real-life examples: [Menu](/examples/menu/index.md), [Simple Planning](/examples/planification-simple/index.md) or [Best Manufacturer Awards](/examples/classification-simple/index.md)

## Nested arrays

Carbone manages nested arrays (unlimited depth). Here is an example where a whole portion of a document is repeated.

```cdata
[
  {
    "brand": "Toyota",
    "models": [{ "size": "Prius 4", "power": 125 }, { "size": "Prius 5", "power": 139  }]
  },
  {
    "brand": "Kia",
    "models": [{ "size": "EV4", "power": 450  }, { "size": "EV6", "power": 500  }]
  }
]
```

```ctemplate
# {d[i].brand}
| Models |
| --- |
| {d[i].models[i].size} - {d[i].models[i].power} |
| {d[i].models[i+1]} |
# {d[i+1]}
```

```cresult
# Toyota
| Models |
| --- |
| Prius 4 - 125 |
| Prius 5 - 139 |
# Kia
| Models |
| --- |
| EV4 - 450 |
| EV6 - 500 |
```

Notice that the whole first block is not repeated: only the closing title `# {d[i+1]}` is needed. This single `[i+1]` marker is enough for Carbone to detect where the outer loop, on the root array `d`, ends.

Get inspired by one of our real-life examples: [Best Selling Vehicles Awards](/examples/awards-simple/index.md) or [Stock Inventory Spreadsheet](/examples/stock-inventory-spreadsheet/index.md)

## Horizontal loops (repeat columns)

A **horizontal loop** repeats **columns** instead of rows. Mark the `[i]` and `[i+1]` positions on two consecutive **columns** of the same row, and Carbone adds one column per array item, growing the table to the right. One difference with the [vertical loop](#simple-array) matters: it closes the whole block with a single `[i+1]`, while a horizontal loop repeats within each row, so every marked row needs its own `[i+1]` end-marker (a bare `{d.array[i+1]}` is enough).

### Example

Here we turn a list of products into columns, one column per product. The first column holds static labels, one per row. The loop fills the rest, adding one product column per array item as it grows to the right:

```cdata
{
  "products": [
    { "name": "Bike",  "price": 200, "stock": 12, "category": "Outdoor" },
    { "name": "Chair", "price": 40,  "stock": 30, "category": "Office"  },
    { "name": "Lamp",  "price": 25,  "stock": 54, "category": "Home"    }
  ]
}
```

**Template:**

| Name | {d.products[i].name} | {d.products[i+1]} |
| --- | --- | --- |
| Price | {d.products[i].price} | {d.products[i+1]} |
| Stock | {d.products[i].stock} | {d.products[i+1]} |
| Category | {d.products[i].category} | {d.products[i+1]} |

**Result:**

| Name | Bike | Chair | Lamp |
| --- | --- | --- | --- |
| Price | 200 | 40 | 25 |
| Stock | 12 | 30 | 54 |
| Category | Outdoor | Office | Home |

Get inspired by one of our real-life examples: [Product Comparison Table](/examples/product-comparison-table/index.md) or [Sensor readings](/examples/sensor-readings/index.md)

## Bi-directional loop

v4.8.0+

The bidirectional loop performs iterations in 2 directions, creating additional columns and rows.

There are a few restrictions:

-   The JSON parent array must be used for rows, and the nested array must be used for columns. This limitation will be removed in Carbone v5.
-   Officially supported in DOCX, HTML, MD templates. In addition, Word can automatically resize the table to fit the page width. Bidirectional loops with other template formats are still experimental. Please get in touch with us in the chat if necessary.

```cdata
{
  "titles" : [{ "name": "Kia" }, { "name": "Toyota" }, { "name": "Hopium" }],
  "cars"   : [
    { "models" : [ "EV3", "Prius 1", "Prototype" ] },
    { "models" : [ "EV4", "Prius 2", "" ]          },
    { "models" : [ "EV6", "Prius 3", "" ]          }
  ]
}
```

**Template:**

| {d.titles[i].name} | {d.titles[i+1].name} |
| --- | --- |
| {d.cars[i].models[i]} | {d.cars[i].models[i+1]} |
| {d.cars[i+1].models[i]} |   |

**Result:**

| Kia | Toyota | Hopium |
| --- | --- | --- |
| EV3 | Prius 1 | Prototype |
| EV4 | Prius 2 |   |
| EV6 | Prius 3 |   |

Get inspired by one of our real-life examples: [Store Inventory](/examples/shoes/index.md) or [Product Comparison Table](/examples/product-comparison-table/index.md)

## Access the loop iterator value

v4.0.0+

Access the iterator value when a list is printed in a document. For example: `{d[i].cars[i].other.wheels[i].tire.subObject:add(.i):add(..i):add(...i)}`

The number of dots corresponds to the position of the `i` in the hierarchy:

-   `...i` refers to the index value of `wheels[i]`
-   `..i` refers to the index value of `cars[i]`
-   `.i` refers to the index value of `d[i]`

> ⚠️ **Warning:** The number of dots is currently inverted. It should be `...i` for `d[i]` and `.i` for `wheels[i]`. This is a known bug. However, many users rely on the current behavior, and fixing it would break some reports. We plan to address this issue in the future while ensuring backward compatibility.

Get inspired by one of our real-life examples: [Summary](/examples/summary/index.md)

## Parallel loop

Iterate through two separate arrays at the same time using the same iterator variable.

As seen [earlier](#access-the-loop-iterator-value), the iterator `i` can be used in formatters.  
By combining it with [relative path access](/documentation/design/formatters/overview.md#dynamic-parameters), we can navigate back in the JSON hierarchy using two dots (`..`).  
This allows us to print the content of another array, `brands`, using the same iterator as the `cars` array.

```cdata
{
  "cars" : [
    { "id" : 1 },
    { "id" : 2 },
    { "id" : 3 },
    { "id" : 4 }
  ],
  "brands" : [
    { "name" : "Toyota" },
    { "name" : "Hyundai"},
    { "name" : "BMW"    }
  ]
}
```

**Template:**

| Cars | id |
| --- | --- |
| {d.cars[i].id} | {d.cars[i].id:print(..brands[.i].name)} |
| {d.cars[i+1].id} |   |

**Result:**

| Cars | id |
| --- | --- |
| 1 | Toyota |
| 2 | Hyundai |
| 3 | BMW |
| 4 |   |

## Array of string/number loop

v4.9.0+

When an array holds plain strings or numbers instead of objects, loop on the value itself with `{d.colors[i]}`, without a property name.

```cdata
{
  "colors": ["Red", "Green", "Blue"]
}
```

**Template:**

| Colors |
| --- |
| {d.colors[i]} |
| {d.colors[i+1]} |

**Result:**

| Colors |
| --- |
| Red |
| Green |
| Blue |

> ℹ️ **Note:** Looped values accept [formatters](/documentation/design/formatters/overview.md) like any other tag, for example `{d.colors[i]:upperCase}`.

## Related topics

- [Loop over object properties](/documentation/design/repetitions/with-objects.md)
- [Sorting arrays](/documentation/design/repetitions/sorting.md)
- [Lookup](/documentation/design/repetitions/lookup.md)
- [Grouping](/documentation/design/repetitions/grouping.md)
- [Filtering arrays](/documentation/design/repetitions/filtering.md)
- [Distinct](/documentation/design/repetitions/distinct.md)
