[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Task](https://evolu.dev/docs/api-reference/common/Task) › each

```ts
function each<TTasks>(
  tasks: TTasks,
  onResult: EachCallback<TTasks>,
  options?: TaskCollectionOptions,
): Task<
  void,
  never,
  ParameterIntersection<
    TTasks[number] extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;
```

Defined in: [packages/common/src/Task.ts:4668](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/Task.ts#L4668)

Runs [Task](https://evolu.dev/docs/api-reference/common/Task/type-aliases/Task)s under a concurrency limit and calls `onResult` for each
Task [Result](https://evolu.dev/docs/api-reference/common/Result/type-aliases/Result) as it settles.

`onResult` receives the [Result](https://evolu.dev/docs/api-reference/common/Result/type-aliases/Result) and the original input index; call
order is settlement order, not input order. Returning `continue` lets queued
Tasks start when capacity is available. Returning `stop` prevents queued
Tasks from starting and aborts already-running Tasks through structured
[Run](https://evolu.dev/docs/api-reference/common/Task/interfaces/Run) disposal — `each` still waits for them to settle before
returning.

`each` is the scheduling primitive under the collection helpers. Each one is
a small `onResult` policy:

| Helper                                                                       | Policy                                                                                        |
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| [all](https://evolu.dev/docs/api-reference/common/Task/functions/all)                     | Collect values, stop on the first [Err](https://evolu.dev/docs/api-reference/common/Result/interfaces/Err) |
| [allSettled](https://evolu.dev/docs/api-reference/common/Task/functions/allSettled)       | Collect every Result, never stop                                                              |
| [any](https://evolu.dev/docs/api-reference/common/Task/functions/any)                     | Stop on the first [Ok](https://evolu.dev/docs/api-reference/common/Result/interfaces/Ok)                   |
| [race](https://evolu.dev/docs/api-reference/common/Task/functions/race)                   | Stop on the first settled Result                                                              |
| [firstN](https://evolu.dev/docs/api-reference/common/Task/functions/firstN)               | Stop after n Ok values                                                                        |
| [firstNSettled](https://evolu.dev/docs/api-reference/common/Task/functions/firstNSettled) | Stop after n Results                                                                          |

Use `each` directly to build a collection policy the helpers don't cover. For
example, keep the first successful value together with its original input
index:

### Example

```ts
import {
  assertEqual,
  assertFalse,
  assertOk,
  createRun,
  each,
  err,
  ok,
  sleep,
  type Task,
  type Typed,
} from "@evolu/common";

let slowCompleted = false;
const slow: Task<string> = async (run) => {
  await run.ok(sleep("10ms"));
  slowCompleted = true;
  return ok("slow");
};
const unavailable: Task<never, ServiceUnavailableError> = () =>
  err({ type: "ServiceUnavailable" });

interface ServiceUnavailableError extends Typed<"ServiceUnavailable"> {}

const tasks = [slow, unavailable, () => ok("fast")] as const;
let first: readonly [string, number] | undefined;
await using run = createRun();
const result = await run(
  each(
    tasks,
    (result, index) => {
      if (!result.ok) return "continue";
      first = [result.value, index];
      return "stop";
    },
    { concurrency: 2 },
  ),
);

assertOk(result, undefined);
assertEqual(first, ["fast", 2]);
assertFalse(slowCompleted);
```

`onResult` is a synchronous scheduling decision, not a place to do work. It
runs in the scheduler's own continuation, bracketed by abort checks, and its
return value gates whether queued Tasks may start. For async work per result,
put it inside the Task itself — the Task is the async slot — or start a
supervised side effect with `void run(task)` from inside the callback and
keep the decision synchronous. Like [RetryOptions.shouldRetry](https://evolu.dev/docs/api-reference/common/Task/interfaces/RetryOptions#shouldretry) and
[RetryOptions.onRetry](https://evolu.dev/docs/api-reference/common/Task/interfaces/RetryOptions#onretry), `onResult` must not throw: a thrown exception is
a defect that panics the Run tree.

Sequential by default; pass a `concurrency` option to run more than one Task
at a time. Defects from child Tasks keep caller-linked async stack traces;
building on `each` preserves diagnostics that a hand-rolled scheduling loop
typically loses.