---
title: "Step decisions"
description: "Execute returns a StepDecision. The decision moves to next Steps,"
canonical_url: "https://docs.superdurable.io/reference/typescript/step-decisions/"
source: "docs/reference/typescript/step-decisions.mdx"
locale: "en"
---

# Step decisions

**Execute** returns a **StepDecision**. The decision moves to next Steps,
closes the Flow, or stops this branch. It can also cancel other Steps.

<a id="gotomulti"></a>

## Multiple next Steps

**GoTo** starts one next Step. **GoToMany** starts multiple next Steps. Each
Step movement has its own input and can also have its own
[Step options](https://docs.superdurable.io/reference/typescript/step-options.md#stepoptions-override-per-stepexecution).

```typescript
return goToMany(
  StepMovement.of(CarrierA, { carrier: "A", price: 10 }),
  StepMovement.of(CarrierB, { carrier: "B", price: 12 }),
  StepMovement.of(Winner, quote),
);
```

Example: [examples/typescript/src/primitives/step-decision/step-decision-flow.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/primitives/step-decision/step-decision-flow.ts)

<a id="close-decisions"></a>

## Close decisions

| Decision             | What it does                                                                                                 |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| **GracefulComplete** | Stops this branch and marks the Flow to complete. The Flow completes when every branch and Step has stopped. |
| **DeadEnd**          | Stops this branch only.                                                                                      |
| **ForceComplete**    | Completes the Flow immediately.                                                                              |
| **ForceFail**        | Fails the Flow immediately.                                                                                  |

**GracefulComplete** and **ForceComplete** can carry an output. **ForceFail**
carries a failure reason. The Flow result lists each output with its Step type
and Step execution ID. When several Steps complete gracefully, the result
contains all their outputs.

**DeadEnd** stops this branch without marking the Flow to complete. A Flow with
no active Steps can keep running.

```typescript
if (mode === "graceful") {
  return gracefulComplete("done");
}
if (mode === "dead-end") {
  return goToMany(
    StepMovement.of(BranchWorker, "left"),
    StepMovement.of(BranchWorker, "right"),
  );
}

return deadEnd();
```

Example: [examples/typescript/src/primitives/step-decision/step-decision-flow.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/primitives/step-decision/step-decision-flow.ts)

```typescript
public execute(_context: Context, _input: void): StepDecision {
  return forceFail("Workflow did not finish the task in time");
}

public execute(_context: Context, _workflowSuccessful: boolean): StepDecision {
  return forceComplete("Workflow completed successfully");
}
```

Example: [examples/typescript/src/patterns/timeout/flow-graceful-timeout.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/patterns/timeout/flow-graceful-timeout.ts)

<a id="cancellation-on-stepdecision"></a>

## Cancel other Steps

A **StepDecision** can cancel other active Steps.

- **CancelSteps** selects active Steps by Step type.
- **CancelSiblingSteps** selects active Steps that were triggered by the same
  parent Step execution.

An RPC can also cancel Steps by type. See
[Cancel running Steps](https://docs.superdurable.io/reference/server/runtime-data.md#cancel-running-steps). For how a
running attempt observes cancellation, see [Cancellation](https://docs.superdurable.io/reference/typescript/step-options.md#cancellation).

When Dex cancels a Step before its **Execute** commits, it returns the Channel
messages that the Step's wait consumed. They go back to the front of their
Channels, in their original order. A Step that the decision cancels also never
receives the messages that the same decision publishes. Neither applies when
the decision also closes the Flow with **ForceComplete** or **ForceFail**. See
[Canceled Steps return consumed messages](https://docs.superdurable.io/reference/server/runtime-data.md#canceled-step-messages).

```typescript
return withCancelingSteps(
  goTo(RecordQuote, quote),
  this.flow.carrierAStep,
  this.flow.carrierBStep,
);
```

Example: [examples/typescript/src/primitives/step-decision/step-decision-flow.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/primitives/step-decision/step-decision-flow.ts)

<a id="forcecompleteifchannelsempty"></a>

## ForceCompleteIfChannelsEmpty

**ForceCompleteIfChannelsEmpty** checks all named Channels in one atomic step.
If every one is empty, it completes the Flow. Otherwise, it goes to the given
next Steps. A Channel with queued messages is non-empty. A Channel also stays
non-empty after a Step consumes a message from it, until that Step's
**Execute** finishes. A message that a canceled Step returned is pending again,
so its Channel is non-empty too.

Use it to complete a Flow once its Channels are drained, so the Flow stays
short. See
[Drain External Channel](https://docs.superdurable.io/design-patterns/draining-channel-for-external-publishing.md)
for the full example.

```typescript
return forceCompleteIfChannelsEmpty(
  null,
  StepMovement.of(ProcessMessage, undefined),
  queueChannel,
);
```

Example: [examples/typescript/src/patterns/drain-channels/external-publishing/draining-channel-flow.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/patterns/drain-channels/external-publishing/draining-channel-flow.ts)
