fork API

fork API

import { fork, type Scope } from "effector";

fork creates an isolated scope of your app. Use it for SSR, testing, or any case where you need to run logic in a safe copy without touching global units.

How it works

  1. Call fork to get a new scope.
  2. If values or handlers are provided, they are applied when the scope is created.
  3. Units run in that scope operate on isolated state and overridden handlers.
  4. Read state via scope.getState(store) or serialize it with serialize.

fork configuration forms

Form
Description
fork()Creates a fresh scope with no prefilled data or handler overrides.
fork({ values?, handlers? })Creates a scope with initial store values and custom effect handlers.
fork(domain, options?)Legacy form that requires domain. Prefer fork({ values?, handlers? }) unless you need old signature compatibility.

Configurations

fork()

Creates a new application scope with default behavior.

  • Formula
fork(): Scope
  • Type
type SerializedState = Record<string, unknown>;
type StorePair<T = unknown> = [StoreWritable<T>, T];
export function fork(config?: {
values?: StorePair<any>[] | SerializedState;
handlers?: Array<[Effect<any, any, any>, Function]>;
}): Scope;
  • Notes

    • Returns a fresh scope without prefilled stores or handler overrides.
    • Use when you need a clean state (e.g., first render on the server).
  • Example

import { createStore, createEvent, fork, allSettled } from "effector";
const inc = createEvent();
const dec = createEvent();
const $counter = createStore(0);
$counter.on(inc, (value) => value + 1);
$counter.on(dec, (value) => value - 1);
const scopeA = fork();
const scopeB = fork();
await allSettled(inc, { scope: scopeA });
await allSettled(dec, { scope: scopeB });
console.log($counter.getState()); // => 0
console.log(scopeA.getState($counter)); // => 1
console.log(scopeB.getState($counter)); // => -1
  • Returns

A new scope.

fork({ values?, handlers? })

Adds initial store values and overrides effect handlers inside the scope.

  • Formula
fork({
values?, // e.g. [[$store, value], ...] or serialized object
handlers?, // e.g. [[effect, handler], ...]
}): Scope
  • Type
type SerializedState = Record<string, unknown>;
type StorePair<T = unknown> = [StoreWritable<T>, T];
export function fork(config?: {
values?: StorePair<any>[] | SerializedState;
handlers?: Array<[Effect<any, any, any>, Function]>;
}): Scope;
  • Notes

    • values can be an array of tuples [$store, value] or a serialized state object (usually from serialize); tuples are preferred.
    • handlers accepts only an array of tuples to override effect handlers; overrides apply only within the created scope.
    • Values and handlers are applied once at scope creation and are not updated automatically.
  • Examples

Set initial state and replace a handler in a test:

import { createEffect, createStore, fork, allSettled } from "effector";
const fetchFriendsFx = createEffect<{ limit: number }, string[]>(async ({ limit }) => {
return [];
});
const $user = createStore("guest");
const $friends = createStore<string[]>([]);
$friends.on(fetchFriendsFx.doneData, (_, result) => result);
const testScope = fork({
values: [[$user, "alice"]],
handlers: [[fetchFriendsFx, () => ["bob", "carol"]]],
});
await allSettled(fetchFriendsFx, {
scope: testScope,
params: { limit: 10 },
});
console.log(testScope.getState($friends));
// => ['bob', 'carol']

Create a scope from serialized state:

import { fork } from "effector";
const serialized = {
userSid: "alice",
ageSid: 21,
};
const scope = fork({ values: serialized });
  • Returns

A new scope with applied values and handlers.

fork(domain, options?)

Legacy form that requires a domain; keep only for compatibility with older code.

Deprecated

Use fork({ values?, handlers? }) because fork tracks units automatically without a domain.

  • Formula
fork(domain, {
values?, // e.g. [[$store, value], ...] or serialized object
handlers?, // e.g. [[effect, handler], ...]
}): Scope
  • Type
type SerializedState = Record<string, unknown>;
export function fork(
domain: Domain,
config?: {
values?: SerializedState | Array<[StoreWritable<any>, any]>;
handlers?: Array<[Effect<any, any, any>, Function]>;
},
): Scope;
  • Notes

    • Pass domain only if your project still depends on the old signature.
    • Allowed values and handlers formats match the configuration without domain.
  • Example

import { createDomain, createStore, fork } from "effector";
const app = createDomain();
const $flag = app.createStore(false);
const scope = fork(app, {
values: [[$flag, true]],
});
console.log(scope.getState($flag)); // => true
  • Returns

A new scope attached to the provided domain.

Contributors