# Pipeline steps

A pipeline is a list of steps. Each step reads and changes the records that reach it, in order. Each kind of step has a page of its own.

## Kinds

| Kind | type | What it does |
| --- | --- | --- |
| [Call](/docs/steps/call) | `call` | Runs another pipeline's steps in place. |
| [Code](/docs/steps/code) | `code` | Runs a program on each record. |
| [Comment](/docs/steps/comment) | `comment` | Holds a note. Records pass it unchanged. |
| [Drop](/docs/steps/drop) | `drop` | Removes each record where a condition is true. |
| [Eval](/docs/steps/eval) | `eval` | Sets fields to the values of expressions. |
| [If](/docs/steps/if) | `if` | Sends each record through one of two lists of steps. |
| [Lookup](/docs/steps/lookup) | `lookup` | Adds fields from the rows of a lookup table that match a value. |
| [Parser](/docs/steps/parser) | `parser` | Reads a text field as JSON, CSV, Key/value or Regex/Grok into fields. |
| [Rename](/docs/steps/rename) | `rename` | Moves fields to new names. |
| [Unroll](/docs/steps/unroll) | `unroll` | Turns each item of an array field into its own record. |

## How it works

Each record goes through the steps from first to last. A step sees what the steps before it wrote. A record a [Drop](/docs/steps/drop) step removes goes no further, and an [Unroll](/docs/steps/unroll) step turns one record into several.

A step's `filter` selects the records it processes: where the filter is false or null, the record passes the step unchanged. An [If](/docs/steps/if) step selects records for a whole list of steps, and gives the other records a list of their own. The pipeline skips a disabled step.

A value a step cannot read or compute throws an exception on its record, such as a parse or math exception. The route's or the group's [exception answers](/docs/routing/exceptions#answers) decide what happens to the record.

## Settings

A step is one entry of its pipeline's steps. Every step takes an `id`:

`id`  string required

The step's name, unique in its pipeline, counting the steps a Call inlines. Errors and exceptions name it.

Examples:

- `parse-json`
- `drop-health-checks`

Every step but If and Comment also takes these:

`filter`  expression default every record

A condition. The step runs only on records where it is true; every other record passes unchanged. Unroll refuses one. The GUI calls it filter.

Examples:

- `status >= 400`
- `path.startsWith("/api/")`
- `source.ip.inCidr("10.0.0.0/8") && action == "deny"`

`disabled`  bool default `false`

Skips the step, so every record passes it unchanged. The GUI's pause button sets it.

## Add a step

1.  Select the worker group and work on a branch.
2.  Open the pipeline, click **\+ step**, and choose the step type.
3.  Fill in its settings, choose a sample, and click **Run now** to preview the output.
4.  Save the pipeline, then [review and deploy](/docs/review).

## Verify

Once the preview is right, choose **Lock this as a test**. After each save, Resources → Samples shows whether every test still gives its locked output. See [Save the result as a test](/build#test-heading).

## Troubleshooting

**A step changes nothing**

Check that it is not disabled and that its filter is true on the sample's records.

**Saving refuses the pipeline**

The message names the step by its id and what it refuses, such as an If condition that is not a bool.

## See also

-   [Expression reference](/docs/code-reference)
-   [Build a first pipeline](/docs/first-pipeline)
-   [Exception answers](/docs/routing/exceptions#answers)
