> For the complete documentation index, see [llms.txt](https://docs.baas.sh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.baas.sh/baas-console/automations/batch.md).

# Batch mode

Repeat an action for matching users, with fixed filters and a shared time budget.

Batch mode repeats an action for each user you select: an Email action then sends one email per user rather than a single message. Every action type can run this way.

You turn it on action by action, so a pipeline can run one step per user and the next one just once.

{% hint style="info" %}
**Batch mode comes with the** [**bolt engine**](/baas-console/console.md)**.** If your project runs on the light engine, batch mode is not offered and each action runs once.
{% endhint %}

## Turn it on

Open the action you want to repeat and turn on **Batch configuration**. Add at least one filter before saving.

## Select the users

**User filters** chooses who the action runs for, with the same rules as everywhere else in the Console. Click **Add filter**, pick a field, an operator and a value:

* `id`, the user's wallet address, and `email` support **=**, **≠**, and **is one of**; email also supports text searches.
* `createdAt`, when the user was created, supports **=**, **≠**, **>**, **≥**, **<** and **≤**.
* Stored contract data uses `contractData.<chainId>.<address>.<dataKey>` for wallet-scoped scalar mappings, in raw units.

With two rules or more, choose **All rules** to keep a user only when every rule matches, so two rules on `createdAt` keep the users created inside a window, or **Any rule** to keep a user when at least one does. Use **Add group** to nest **All rules (AND)** and **Any rule (OR)** groups, each with its own choice. A batch without a filter is refused; empty groups and `where: null` are invalid. Operators, values and limits are on the [Filters](/baas-console/filters.md) page.

For example, to email users who joined in September, choose **All rules**, then add `createdAt` **≥** `2026-09-01 00:00` and `createdAt` **<** `2026-10-01 00:00`.

For data stored per key, each rule may match a different key. Two rules do not necessarily describe the same balance or item.

{% hint style="info" %}
**Filters use fixed values.** Enter the selection criteria when configuring the action; they cannot come from the trigger or a previous action.
{% endhint %}

Through the API or MCP, a supplied `batch` must contain a non-empty `where`, on creation and update. Omit `batch` on update to leave it unchanged; send `batch: null` to disable it, adjusting batch-dependent config in the same update.

## Time budget

The batch processes matching users newest first, with no total user cap. Selection reads current data as it progresses; changes made during the run can affect which users are selected.

The system gives the entire batch up to **300 seconds**, or a lower configured limit. All users share that budget. At timeout, processing stops. Completed effects remain, and an in-flight call may still take effect.

### Estimate batch capacity

These results come from one test per action with 200,000 selected users on a 1 CPU / 512 MiB deployment, using a fast HTTP endpoint and a private blockchain:

| Action per user        | Successful users recorded within 300 seconds |
| ---------------------- | -------------------------------------------: |
| Appel API HTTP direct  |                                       13,666 |
| Function JavaScript    |                                        2,937 |
| Transaction blockchain |                                        1,348 |

Use these figures as estimates. Your throughput depends on the work each action performs, API latency and network conditions. Blockchain transactions are counted when accepted for sending; confirmation can happen later.

## What each repetition reads

A batched action reads the user it is running for:

| Variable                          | What it holds                                                                        |
| --------------------------------- | ------------------------------------------------------------------------------------ |
| `context.batch.user.id`           | The user's wallet address                                                            |
| `context.batch.user.email`        | The user's email                                                                     |
| `context.batch.user.fcmTokens`    | The user's device tokens                                                             |
| `context.batch.user.createdAt`    | When the account was created: passkey sign-up, or an external wallet's first sign-in |
| `context.batch.user.contractData` | The [on-chain data](/baas-console/users/explorer.md#user-data) kept for the user     |
| `context.batch.index`             | The user's position in the batch, starting at `0`                                    |

`trigger`, `context.previous`, and the run identifiers are shared across users; `context.batch` changes per user, and the remaining time decreases during execution.

## What batch changes per type

| Action                                                                                                        | In batch mode                                                                       |
| ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| [Email](/baas-console/automations/actions/email.md)                                                           | The recipient is set to the batch user's email                                      |
| [Notification](/baas-console/automations/actions/notification.md)                                             | The push goes to the batch user's device tokens, and a user without any is skipped  |
| [Transaction](/baas-console/automations/actions/transaction.md)                                               | Only **Accepted (queued)** is available, so the step never waits for a confirmation |
| [API](/baas-console/automations/actions/api.md) and [Function](/baas-console/automations/actions/function.md) | Nothing is set for you                                                              |

## If one user fails

The batch stops there. Completed effects are not undone. The saved `batchProgress` reports started and confirmed-success counts, the last confirmed user cursor, and any unconfirmed user. An unconfirmed user may already have produced an effect.

A batched action is never retried automatically. A new run starts selection over; it does not resume from the saved cursor and may repeat completed effects.

{% hint style="info" %}
**A batch hands nothing to the next step.** A batched step produces one result per user, so the next step reads `context.previous` as `null`. Put the batch last, or write `{{context.previous?}}` in the step that follows.
{% endhint %}

## Follow it in the logs

In the [run's logs](/baas-console/automations/runs-and-logs.md), a [Function](/baas-console/automations/actions/function.md) running in batch tags each `console.log` line with the user it ran for, numbered by position in the batch. The action's own start and end lines cover the whole batch. Its saved counters and cursors appear in the terminal log and the API's run-action `batchProgress`; they are not live counters. A crash before saving can leave progress unknown.

## Next

* [Runs and logs](/baas-console/automations/runs-and-logs.md): follow a batched run and read what it recorded.
* [Users](/baas-console/users.md): browse the users a batch can select.
* [Actions](/baas-console/automations/actions.md): set up the action a batch repeats.
