> For the complete documentation index, see [llms.txt](https://docs.contextual.io/documentation-and-resources/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.contextual.io/documentation-and-resources/components-and-data/flows/node-reference/stream/filter.md).

# Filter

Keeps or drops each item in a source stream based on an expression.

**Not the same node as the Filter under Function.** The Palette has two different nodes named *Filter*. This page covers the one in the **Stream** group: it evaluates a JSONata expression you write — for example `payload.temperature > 5` — against each item in a source stream and drops the ones that don't match. The other *Filter*, in the **Function** group, is a different node entirely: a Report-by-Exception node with no expression field at all. Its **Mode** setting blocks a message unless the payload has changed since the last one it saw, with variants for ignoring the initial value or for gating on the size of a numeric change instead of any change at all (for example, "block unless value change is greater than") — built for suppressing duplicate or near-duplicate readings, not for testing arbitrary conditions. If the node on your canvas has an **Expression** property, you have the one documented here; if its configuration is about detecting changed values instead, you have the Function-group node. See *Choosing between Source From, Loop, and Split/Join* on the *Source From* page for how streams relate to other iteration approaches in a Flow.

A source stream carries items one at a time, each travelling as its own message. **Filter** evaluates an expression against every item and decides whether it continues. Items that satisfy the expression pass through unchanged; items that do not are dropped from the stream.

Use a **Filter** node in your Flow to narrow a stream to the items you care about — records above a threshold, entries matching a status, rows with a required field present — before doing further work on them. Filtering inside the stream means later nodes run only for the items that matter, and the collected result contains only those items.

Filter only works inside a stream. It must sit downstream of a node that opens one, such as *Source From* or a *Query Object* node with **Unfold all pages to source** enabled. *Filter requires a source stream*.

To configure a **Filter** node in the *Flow Editor*, drag it from the **Stream** group in the Palette to the Workspace canvas, then double-click the node to open and configure its behavior.

## Properties

* **Name** — optional display name for the node in the editor. By default the node shows a label of "Filter"; the value you provide here replaces it, making your flow easier to read.
* **Expression** — a JSONata expression evaluated once for each item. If it returns true, the item continues down the stream. If it returns false, the item is dropped.

## Writing the expression

Reference properties of the message directly, without a msg. prefix. The item being evaluated is at payload, so a weather record's temperature is payload.temperature.

```
payload.temperature > 5
```

**Do not mix the `payload` and `msg.payload` styles in the same expression.** Both work on their own, but combining them — for example `payload.temperature > 5 and msg.payload.humidity > 10` — evaluates against inconsistent scopes and silently returns an unexpected result rather than an error. If the expression editor shows a **Compatibility mode enabled** notice, an expression somewhere still references `msg`; fix it by removing the `msg.` prefix from that expression, not by adding `msg.` to the rest of it.

Because the field takes a full JSONata expression rather than a fixed operator list, comparisons can be combined and values transformed before being tested:

| **Expression**                                            | **Keeps**                                                   |
| --------------------------------------------------------- | ----------------------------------------------------------- |
| payload.temperature > 5                                   | Items with a temperature above 5                            |
| payload.stationId = 'Dallas'                              | Items from one station, matched exactly                     |
| $lowercase(payload.stationId) = 'Dallas'                  | The same, ignoring case                                     |
| payload.temperature > 5 and payload.stationId != 'Irving' | Both conditions together                                    |
| payload.datetime                                          | Items where datetime evaluates to a JavaScript-truthy value |

An expression that does not resolve against an item — for example payload.temperature where payload is a string — returns no result, and the item does not pass.

## The expression editor

Selecting the **`...`** button beside the **Expression** field opens the JSONata Expression editor, which is worth using for anything beyond a simple comparison:

* **format expression** tidies the layout of a long expression.
* **Function reference** lists JSONata's built-in functions with their signatures and descriptions and inserts the selected one into the expression. This is how to discover helpers such as $lowercase, $contains and $abs.
* **Test** evaluates the expression against an example message you provide and shows the result immediately.

The **Test** tab is the fastest way to confirm an expression before deploying. Paste one item into **Example message** in the shape it will arrive in:

```json
{
  "payload": {
    "temperature": 12,
    "stationId": "Dallas"
  }
}
```

**Result** shows true, so an item like this one would pass. Changing the temperature to 4 returns false. If **Result** shows No matching result, the expression did not resolve against the example — usually a path that does not exist in the message.

## Filter requires a source stream

A Filter node must sit downstream of a node that opens a source stream. The editor marks a Filter outside a source with a lint error:

```
Lint Errors:

- Does not have a source
```

Connecting Filter within a source stream clears the lint error. If Filter is nevertheless invoked without a source, it also reports the runtime error `source not initialized` and sends no output.

## Example

A weather application stores readings as records of the **weather app** Object Type. The /report3 endpoint returns only the warmer readings, discarding the rest before they reach the caller.

```
[GET] /report3 → [Source] Query Objects → Filter → Sink Collect → HTTP Response
```

### Open a stream

Configure the Query Objects node with **Type Id** weather app, **Query** {}, **Page Size** 10, and **Unfold all pages to source** enabled. Ten records are emitted, each as its own message.

### Configure the Filter node

Set **Expression** to:

```
payload.temperature > 5
```

### Collect and respond

Add a *Sink Collect* node to close the stream, then an HTTP Response node.

### Confirm the result

Place a Log node between Filter and Sink Collect and request /report3. With stored temperatures of 12, 13, 1, 4, 8, 4, 9, 10, 2 and 5, only five records pass:

```
{ temperature: 12, stationId: "dallas", ... }

{ temperature: 13, stationId: "irving", ... }

{ temperature: 8, stationId: "fort worth", ... }

{ temperature: 9, stationId: "houston", ... }

{ temperature: 10, stationId: "austin", ... }
```

The reading of exactly 5 is excluded, because the comparison is strictly greater than. A Log node placed after Sink Collect shows a single entry containing an array of five.

Items that pass are unchanged. Filter determines what continues, it does not modify anything. To reshape the items that survive, add a *Map* node after the Filter.

### When nothing matches

If no item satisfies the expression, no item-level work attached to the source runs. The carrier message still continues through downstream nodes, and *Sink Collect* consumes the empty source and emits one message containing an empty array. The endpoint therefore returns \[] rather than hanging or failing.

Changing the expression above to payload.temperature > 999 produces no entries at the Log node between Filter and Sink Collect, and a single array\[0] at the Log node after it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.contextual.io/documentation-and-resources/components-and-data/flows/node-reference/stream/filter.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
