# retry (/docs/macros/retry)



A publish, deploy, or upload step that leans on an external service fails
intermittently — a transient 502, a rate limit, a flaky registry — and one blip
shouldn't redden the whole run. `retry` re-runs the **same step on the same runner**
up to N times with optional backoff; the first success clears it. Works with both
`run:` and `uses:` steps. When the failure is the **runner itself** (OOM, too few
cores), reach for [`fallback.retry`](/docs/macros/fallback#retry-different-runner)
instead — it re-runs the step once in a fresh job on a different `runs-on`.

Fans out into conditional attempts, each gated on prior failure:

<CodeCompare>
  ```yaml title=".actio.yml"
  jobs:
    deploy:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v4
        - name: Deploy to production
          uses: cloudflare/wrangler-action@v3
          retry:
            attempts: 3
            delay: 10s
          with:
            apiToken: ${{ secrets.CF_API_TOKEN }}
  ```

  ```yaml title="generated .yml"
  jobs:
    deploy:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v4
        - name: Deploy to production (attempt 1/3)
          uses: cloudflare/wrangler-action@v3
          id: step_deploy_to_production_attempt_1 # [!code highlight:2]
          continue-on-error: true
          with:
            apiToken: ${{ secrets.CF_API_TOKEN }}
        - name: Retry backoff (10s) before attempt 2/3 # [!code highlight:3]
          run: sleep 10
          if: steps.step_deploy_to_production_attempt_1.outcome == 'failure'
        - name: Deploy to production (attempt 2/3)
          uses: cloudflare/wrangler-action@v3
          id: step_deploy_to_production_attempt_2 # [!code highlight:3]
          if: steps.step_deploy_to_production_attempt_1.outcome == 'failure'
          continue-on-error: true
          with:
            apiToken: ${{ secrets.CF_API_TOKEN }}
        - name: Retry backoff (10s) before attempt 3/3 # [!code highlight:3]
          run: sleep 10
          if: steps.step_deploy_to_production_attempt_2.outcome == 'failure'
        - name: Deploy to production (attempt 3/3)
          uses: cloudflare/wrangler-action@v3
          id: step_deploy_to_production_attempt_3 # [!code highlight:2]
          if: steps.step_deploy_to_production_attempt_2.outcome == 'failure'
          with:
            apiToken: ${{ secrets.CF_API_TOKEN }}
  ```
</CodeCompare>

## How it works [#how-it-works]

* Each attempt but the last gets `continue-on-error: true` so failure doesn't stop the job.
* Attempt N runs only when attempt N-1 had `outcome == 'failure'`.
* A success at any attempt short-circuits the rest; all-fail fails the job on the final attempt.
* Each attempt gets a unique ID and auto-names as `"<step> (attempt N/max)"`.

## Options [#options]

<TypeTable
  type="{
  attempts: {
    description: 'Number of times to retry (minimum 2).',
    type: 'number',
    required: true,
  },
  delay: {
    description: 'Backoff between attempts, e.g. &#x22;10s&#x22;, &#x22;2m&#x22;, &#x22;1h&#x22; (injects sleep steps).',
    type: 'string',
  },
}"
/>

<Callout title="Shorthand">
  `retry: 3` is the same as `retry: { attempts: 3 }`.
</Callout>


## Sitemap

Browse the full documentation: [Markdown sitemap](https://austenstone.github.io/actio/sitemap.md) · [XML sitemap](https://austenstone.github.io/actio/sitemap.xml)