# Retrying Steps

import { Aside, CardGrid, LinkCard } from "@astrojs/starlight/components";

Configure retry behavior based on step reliability characteristics. Set conservative flow-level defaults and override per-step as needed.

<Aside type="tip">
For scheduling delays between steps, see [Delaying Steps](/build/delaying-steps/).
</Aside>

For detailed information about each configuration option, see the [Step Execution Options](/reference/configuration/step-execution/) reference.

## Understanding Failure Types

Not all failures should retry. Understanding the difference helps you configure appropriate retry policies.

### Transient Failures

Temporary problems that might succeed on retry:
- Network timeouts
- Rate limiting (429 responses)
- Temporary service unavailability (503 responses)
- Database connection issues

Configure with retries:
```typescript
.step({
  slug: 'fetchExternalData',
  maxAttempts: 5,   // Retry transient failures
  baseDelay: 2,
}, async (input) => await fetchFromAPI(input.run.url))
```

### Permanent Failures

Problems that will never succeed on retry:
- Invalid input format (malformed email, negative numbers)
- Missing required fields
- Business rule violations
- Schema validation errors

Configure without retries:
```typescript
.step({
  slug: 'validInput',
  maxAttempts: 1,   // No retries for validation
}, (input) => {
  if (!input.run.email) throw new Error('Email required');
  return input.run;
})
```

<Aside type="note">
`maxAttempts: 1` means "run once, do not retry". If the step fails, it fails immediately without retry attempts.
</Aside>

<Aside type="caution" title="Current Limitation">
pgflow does not distinguish between transient and permanent failures automatically. All exceptions trigger retry logic based on `maxAttempts`. Use `maxAttempts: 1` for steps that perform validation or other operations that should fail fast.
</Aside>

For detailed guidance on validation patterns, see [Validation Steps](/build/validation-steps/).

## Guiding Principle

**Set conservative flow-level defaults, override per-step as needed.**

Most flows contain a mix of operations - some reliable (database writes), some flaky (external APIs), some that should fail fast (validation). Rather than applying aggressive retry policies to all steps, start with sensible defaults and override specific steps based on their failure characteristics.

## Recommended: Per-Step Configuration

When different steps have different reliability requirements:

```typescript
new Flow({
  slug: 'data_pipeline',
  maxAttempts: 3,     // Sensible defaults
  baseDelay: 1,
})
  .step({
    slug: 'validate_input',
    maxAttempts: 1,   // No retries - validation should not fail
  }, validateHandler)
  .step({
    slug: 'fetch_external',
    maxAttempts: 5,   // External API might be flaky
    baseDelay: 10,    // Longer delays for external service
  }, fetchHandler)
  .step({
    slug: 'save_results',
    // Use flow defaults
  }, saveHandler)
```

**Why this approach:**
- Set reasonable flow-level defaults
- Override only where needed
- Validation steps need no retries (fail immediately on bad input)
- External API steps need more retries and longer delays
- Simple database operations use defaults

## Learn More

<CardGrid>
  <LinkCard
    title="Validation Steps"
    href="/build/validation-steps/"
    description="Use explicit validation steps to fail fast on invalid input"
  />
  <LinkCard
    title="Step Execution Options"
    href="/reference/configuration/step-execution/"
    description="Complete reference for all configuration options and their defaults"
  />
  <LinkCard
    title="Delaying Steps"
    href="/build/delaying-steps/"
    description="Schedule steps to run after specified delays"
  />
  <LinkCard
    title="Worker Configuration"
    href="/reference/configuration/worker/"
    description="Configure Edge Worker concurrency and polling behavior"
  />
  <LinkCard
    title="Tune Deployed Flows"
    href="/deploy/tune-flow-config/"
    description="Adjust configuration for production flows without redeploying"
  />
</CardGrid>