# Writing flows

A flow is a YAML file that walks through one journey in your app. Each step names the control it acts on by what it is, such as its testID or label, not by where it sits on the screen, so the flow keeps working when the layout changes.

## A flow file

Flows live in `.squiggle/flows/`. This one signs in, adds a product to the cart and checks out:

```yaml
flow: checkout
env:
  USER: dana@example.com
steps:
  - runFlow: { file: login.yaml }
  - tap: { testID: product-1 }
  - tap: { text: Add to cart }
  - tap: { testID: checkout }
  - assert: { route: OrderConfirmation }
  - assert: { visible: { text: "Order placed" } }
```

`flow` is the name you run it by: `squiggle flow checkout`. `env` holds test data that steps use as `${USER}`. `steps` is the journey: each step is one action or check. The [Flow syntax](https://squiggle.sh/docs/reference/flow) reference lists every key and step.

## What makes a good flow

- **One journey per file.** Sign-in, add to cart and checkout are three flows. Join them with `runFlow` instead of writing one long file.
- **Name controls by what they are.** A `testID` survives copy edits, translations and redesigns. See [Selectors](https://squiggle.sh/docs/flows/selectors).
- **End with an assert.** A tap passes once it reaches the button, whether or not the app reacted. Check the result. See [Assertions](https://squiggle.sh/docs/flows/assertions).
- **Never sleep.** Squiggle waits for the app to stop moving before each step. To wait for something specific, use `waitFor`.

## Run it

```shell
squiggle flow checkout
```

The same file runs in Studio, in CI and from your coding agent. See [Run flows](https://squiggle.sh/docs/run).

## In this section

- [Selectors](https://squiggle.sh/docs/flows/selectors): How a step finds the control it acts on.
- [Assertions](https://squiggle.sh/docs/flows/assertions): Check the result of a step, not only that it ran.
- [Healing](https://squiggle.sh/docs/flows/healing): When a control moves, the flow finds it again.
- [Repeatable flows](https://squiggle.sh/docs/flows/repeatable): Start state, network stubs, reuse and control flow.
- [Bad networks](https://squiggle.sh/docs/flows/network): Slow, failing and offline runs of a flow.
- [App state](https://squiggle.sh/docs/flows/state): Find the saved values that make a flow fail.
- [Gestures and scrolling](https://squiggle.sh/docs/flows/gestures): Swipes, scrolls, drags and off-screen controls.
- [Record and crawl](https://squiggle.sh/docs/flows/record): Draft a flow by using the app, or let it explore.
- [Coming from Maestro](https://squiggle.sh/docs/flows/maestro): What carries over from Maestro, and what doesn’t.

Moving from Maestro? See [Coming from Maestro](https://squiggle.sh/docs/flows/maestro). To write a step as a goal and let your coding agent work out the taps, see [Agentic flows](https://squiggle.sh/docs/agentic-flows).
