> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/vercel/workflow/llms.txt
> Use this file to discover all available pages before exploring further.

# getStepMetadata

> Get metadata about the currently executing step

Returns metadata about the currently executing step function, including the step ID, start time, and attempt number.

## Signature

```typescript theme={null}
function getStepMetadata(): StepMetadata
```

## Returns

<ResponseField name="StepMetadata" type="StepMetadata">
  Metadata about the current step.

  <Expandable title="properties">
    <ResponseField name="stepId" type="string">
      Unique identifier for the currently executing step.

      Useful as part of an idempotency key for critical operations that must only be executed once (such as charging a customer).
    </ResponseField>

    <ResponseField name="stepStartedAt" type="Date">
      Timestamp when the current step started.
    </ResponseField>

    <ResponseField name="attempt" type="number">
      The number of times the current step has been executed. This will increase with each retry.

      Starts at 1 for the first execution.
    </ResponseField>
  </Expandable>
</ResponseField>

## Usage

### Basic Usage

Get step metadata inside a step function:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function workflowWithStepMetadata() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const metadata = getStepMetadata();
    
    console.log('Step ID:', metadata.stepId);
    console.log('Started at:', metadata.stepStartedAt);
    console.log('Attempt:', metadata.attempt);
  });
}
```

### Idempotency Key

Use the step ID as an idempotency key for critical operations:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function chargeCustomer(amount: number) {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { stepId } = getStepMetadata();
    
    // Use stepId as idempotency key to prevent double-charging
    await stripe.charges.create({
      amount,
      currency: 'usd',
      idempotency_key: stepId,
    });
  });
}
```

### Retry Tracking

Track retry attempts:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function workflowWithRetries() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { attempt } = getStepMetadata();
    
    console.log(`Attempt ${attempt}`);
    
    if (attempt > 1) {
      console.log('This is a retry');
    }
    
    // Perform operation
    await riskyOperation();
  });
}
```

### Conditional Logic Based on Attempts

Adjust behavior based on retry count:

```typescript theme={null}
import { step, getStepMetadata, RetryableError } from 'workflow';

export async function workflowWithConditionalRetry() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { attempt } = getStepMetadata();
    
    try {
      if (attempt > 3) {
        // Use a longer timeout for later attempts
        await fetchWithTimeout(url, { timeout: 30000 });
      } else {
        await fetchWithTimeout(url, { timeout: 5000 });
      }
    } catch (error) {
      if (attempt < 5) {
        // Exponential backoff
        throw new RetryableError(
          'Fetch failed, retrying',
          { retryAfter: Math.pow(2, attempt) * 1000 }
        );
      }
      throw error;
    }
  });
}
```

### Logging with Step Context

Include step metadata in logs:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function workflowWithStepLogging() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { stepId, stepStartedAt, attempt } = getStepMetadata();
    
    console.log({
      stepId,
      startedAt: stepStartedAt.toISOString(),
      attempt,
      message: 'Processing data',
    });
    
    await processData();
  });
}
```

### Unique File Names

Generate unique file names per step:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function workflowWithFileGeneration() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { stepId } = getStepMetadata();
    const filename = `report-${stepId}.pdf`;
    
    await generateReport(filename);
    await uploadFile(filename);
  });
}
```

### Combining with Workflow Metadata

Use both step and workflow metadata:

```typescript theme={null}
import { step, getStepMetadata, getWorkflowMetadata } from 'workflow';

export async function workflowWithCombinedMetadata() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const stepMeta = getStepMetadata();
    const workflowMeta = getWorkflowMetadata();
    
    console.log({
      workflowRunId: workflowMeta.workflowRunId,
      stepId: stepMeta.stepId,
      stepAttempt: stepMeta.attempt,
    });
  });
}
```

### Calculate Step Duration

Track how long a step has been running:

```typescript theme={null}
import { step, getStepMetadata } from 'workflow';

export async function workflowWithDuration() {
  "use workflow";

  await step(async () => {
    "use step";
    
    const { stepStartedAt } = getStepMetadata();
    
    await performWork();
    
    const duration = Date.now() - stepStartedAt.getTime();
    console.log(`Step completed in ${duration}ms`);
  });
}
```

## Notes

* Can only be called inside a step function (with `"use step"`)
* Throws an error if called from a workflow function
* Uses `AsyncLocalStorage` to retrieve the step context
* The `stepId` is guaranteed to be unique for each step execution
* The `attempt` number starts at 1 and increments with each retry
* The `stepStartedAt` timestamp represents when the current attempt started, not when the step was first attempted

## Related

* [getWorkflowMetadata](/api-reference/workflow/get-workflow-metadata) - Get workflow run metadata
* [RetryableError](/api-reference/workflow/retryable-error) - Control step retry behavior
* [getWritable](/api-reference/workflow/get-writable) - Get a writable stream for the workflow


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.