Skip to main content


Takes the input step (or array of steps, or nothing) as the first argument, a callback as the second argument, and returns a step that represents the result of feeding each value (or array of values, or nothing) through the given callback.

The callback is expected to have a side effect (change data or state on the backend), if your callback doesn't have any side effects then consider using lambda instead, it has a very similar API.


Side effects, according to the GraphQL spec, are only expected to occur in the root selection set of a GraphQL mutation operation (i.e. on the fields of the mutation operation root type), similarly Grafast only expects side effects here and side effects in other locations in the plan may have unexpected repercussions.

sideEffect does not perform batching; it is only intended for performing mutations, and mutations rarely batch.


Almost any step can be made to be treated as having side effects by setting $step.hasSideEffects = true, so if you require batching in your mutations consider using an alternative step, such as loadOne() and explicitly marking it as having side effects:

const $random = loadOne(list([$min, $max]), (tuples) =>[min, max]) => min + Math.floor(Math.random() * (max - min + 1))),
$random.hasSideEffects = true;

return $random;

Single dependency version

function sideEffect<T, R>(
$input: ExecutableStep<T>,
callback: (input: T) => R | Promise<R>,
): ExecutableStep<R>;


const $logout = context().get("logout");
sideEffect($logout, (logout) => logout());

Dependency-free version

If your callback doesn't need any input then you can pass null or undefined instead of a step.

function sideEffect<R>(
$input: null | undefined,
callback: () => R | Promise<R>,
): ExecutableStep<R>;


sideEffect(null, () => console.log(new Date().toISOString()));

Multiple dependencies version

If you need to pass multiple steps, you can use the list() step to do so: sideEffect(list([$a, $b, $c]), ([a, b, c]) => doSomethingWith(a, b, c)).

If you'd prefer to save a few characters you can pass the array of steps directly and we'll automatically wrap it in list() for you:

function sideEffect<Tuple extends [...any[]], R>(
// i.e. $input: ExecutableStep[],
$input: { [Index in keyof Tuple]: ExecutableStep<Tuple[Index]> },
callback: (input: Tuple) => R | Promise<R>,
): ExecutableStep<R>;


sideEffect([$login, $username, $password], ([login, username, password]) =>
login(username, password),