> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/harness-platform/3.0/harness-platform-resources/overview/strategy.md).

# Execution controls

Use a looping strategy to run a stage or step multiple times; iterate a fixed number of times with a for loop, loop conditionally with a while loop, or fan out across input combinations with a matrix.

A **strategy** tells Harness to run a stage or step more than once. Instead of duplicating stages or steps for each environment, region, or input combination, you define the variation once and let the strategy expand it at runtime.

Strategy can be applied at the **stage level** (each instance runs as a separate stage) or the **step level** (each instance runs as a separate step within the same stage).

## What you will learn

* How to use for loop, while loop, and matrix strategies to run a stage or step multiple times
* How matrix fans out across combinations of values and how to reference axis values in steps
* How to exclude specific matrix combinations and customize instance names with `node-name`
* How `max-parallel` and `fail-fast` control strategy execution behavior

The Strategy panel has three shared settings that apply to all strategy types:

| Field             | Description                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------- |
| **Max parallel**  | Maximum number of strategy instances that run simultaneously. Set to `0` for unlimited (default). |
| **Fail fast**     | When `true`, cancels all running instances if any one instance fails.                             |
| **Strategy type** | The looping type: **For loop**, **While loop**, or **Matrix**.                                    |

***

## For loop

A for loop runs the stage a fixed number of times. Each iteration runs as a separate stage instance. By default, all instances run in **parallel**.

```yaml
stages:
  - name: build
    id: build
    strategy:
      max-parallel: 0
      fail-fast: true
      for:
        iterations: 3
    steps:
      - name: run
        id: run
        run:
          script: |
            echo "Iteration: ${{ strategy.iteration }}"
            echo "Total: ${{ strategy.iterations }}"
```

**Verified expression output** for 2 iterations:

| Expression                   | Resolves to                                 |
| ---------------------------- | ------------------------------------------- |
| `${{ strategy.iteration }}`  | Current iteration index (0-based): `0`, `1` |
| `${{ strategy.iterations }}` | Total number of iterations: `2`             |

**Stage naming**: each instance is named `<stage_id>_<index>`. A stage with `id: build` and `iterations: 3` produces `build_0`, `build_1`, `build_2`.

{% hint style="info" %}
`for` only accepts integer `iterations`. A list of string items is not supported.
{% endhint %}

***

## While loop

A while loop runs the stage up to a maximum number of iterations. Each iteration runs **sequentially**; the next instance starts only after the previous one finishes.

```yaml
stages:
  - name: poll
    id: poll
    strategy:
      max-parallel: 0
      fail-fast: false
      while:
        iterations: 3
    steps:
      - name: check
        id: check
        run:
          script: |
            echo "While iteration: ${{ strategy.iteration }}"
            echo "Total: ${{ strategy.iterations }}"
```

**Stage naming** follows the same pattern as for loop: `poll_0`, `poll_1`, `poll_2`.

{% hint style="info" %}
Unlike the for loop, while loop instances always run one at a time regardless of `max-parallel`.
{% endhint %}

***

## Matrix

A matrix runs the stage once for every combination of values across one or more axes. All combinations run in **parallel** by default. The total number of instances is the product of all axis lengths minus any excluded combinations.

### Basic example

```yaml
stages:
  - name: test
    id: test
    strategy:
      max-parallel: 2
      fail-fast: true
      matrix:
        os:
          - linux
          - windows
        node:
          - "18"
          - "20"
    steps:
      - name: run-tests
        id: run_tests
        run:
          script: |
            echo "OS: ${{ matrix.os }}"
            echo "Node: ${{ matrix.node }}"
```

This produces four instances (all 2×2 combinations):

| Instance   | `${{ matrix.os }}` | `${{ matrix.node }}` |
| ---------- | ------------------ | -------------------- |
| `test_0_0` | `linux`            | `18`                 |
| `test_0_1` | `linux`            | `20`                 |
| `test_1_0` | `windows`          | `18`                 |
| `test_1_1` | `windows`          | `20`                 |

**Stage naming** uses axis index pairs: `<stage_id>_<axis1_index>_<axis2_index>`.

***

### Browser and OS testing

Run a test suite across every browser/OS combination with a concurrency cap to avoid overloading infrastructure:

```yaml
strategy:
  max-parallel: 3
  fail-fast: false
  matrix:
    browser:
      - chrome
      - safari
      - firefox
    os:
      - macos
      - windows
      - linux
```

Produces 9 combinations. Reference values in steps with `${{ matrix.browser }}` and `${{ matrix.os }}`.

***

### JDK version matrix (single axis)

A single-axis matrix is the simplest form: run the same stage once for each value in a list. With `max-parallel` set, instances beyond the cap queue until a slot opens:

```yaml
strategy:
  max-parallel: 2
  matrix:
    jdk:
      - "21"
      - "17"
      - "11"
```

Reference the current JDK version with `${{ matrix.jdk }}`. Single-axis instances are named `<stage_id>_0`, `<stage_id>_1`, `<stage_id>_2` (not `_0_0` like multi-axis).

***

### Service × environment deployment

Deploy multiple services to multiple environments, with a specific combination excluded:

```yaml
strategy:
  max-parallel: 2
  fail-fast: false
  matrix:
    service:
      - api
      - worker
      - scheduler
    environment:
      - staging
      - production
    exclude:
      - service: scheduler
        environment: production
```

This produces 5 instances (3×2 = 6, minus 1 excluded). Reference with `${{ matrix.service }}` and `${{ matrix.environment }}`.

***

### Exclude combinations

**Exclude a specific pair:**

```yaml
matrix:
  os:
    - linux
    - windows
  node:
    - "18"
    - "20"
  exclude:
    - os: windows
      node: "18"
```

**Exclude all combinations containing a value** (omit one key to match any pairing):

```yaml
matrix:
  browser:
    - chrome
    - safari
    - firefox
  os:
    - macos
    - windows
    - linux
  exclude:
    - os: macos
```

This removes all three `macos` combinations, producing 6 instances instead of 9.

***

### Custom instance names with node-name

By default, instances are named `<stage_id>_0_0`, `<stage_id>_0_1`, etc. Use `node-name` to give instances meaningful names:

```yaml
strategy:
  matrix:
    service:
      - api
      - worker
    environment:
      - staging
      - production
    node-name: "${{ matrix.service }}-${{ matrix.environment }}"
```

This produces stage identifiers: `deploy_api_staging`, `deploy_worker_staging`, `deploy_api_production`, `deploy_worker_production`.

{% hint style="info" %}
Hyphens in the resolved `node-name` are converted to underscores in the stage identifier. The original stage id is prepended: `<stage_id>_<node-name>`.
{% endhint %}

{% hint style="info" %}
Avoid hyphens in axis names (e.g. use `nodeVersion` not `node-version`). Hyphens in axis names cause expressions like `${{ matrix.node-version }}` to resolve as null.
{% endhint %}

***

## Comparison

|                              | For loop                    | While loop                  | Matrix                  |
| ---------------------------- | --------------------------- | --------------------------- | ----------------------- |
| **Input**                    | Integer count               | Integer count               | One or more value lists |
| **Default execution**        | Parallel                    | Sequential                  | Parallel                |
| **Stage naming**             | `<id>_0`, `<id>_1`          | `<id>_0`, `<id>_1`          | `<id>_0_0`, `<id>_0_1`  |
| **Current value expression** | `${{ strategy.iteration }}` | `${{ strategy.iteration }}` | `${{ matrix.<axis> }}`  |

***

## Next steps

* Go to [Concurrency](/harness-platform/3.0/harness-platform-resources/overview/strategy/concurrency.md) to limit parallel instances with `max-parallel`.
* Go to [Pipelines overview](/harness-platform/3.0/harness-platform-resources/overview.md) to review the pipeline model.
