What is a "domain"?
In Effector, a domain is a container that groups related parts of the logic together:
store, event, effect, sample, and so on.
Put simply:
A domain is an "area of responsibility" (a feature module) that holds all the related state, events, and effects.
1. What a Domain is conceptually
Effector is a reactive system where you can create many events and stores. As a project grows, there can be hundreds of them, and you need to organize all of that.
This is where Domain helps: it creates hierarchy, encapsulation, and a single point of control for a module.
2. Example of the simplest Domain
import { createDomain } from 'effector'
// create a domain
const userDomain = createDomain('user')
// create events, stores, and effects inside it
const fetchUserFx = userDomain.createEffect(async (id: number) => {
const res = await fetch(`/api/users/${id}`)
return res.json()
})
const userLoaded = userDomain.createEvent()
const $user = userDomain.createStore(null)
.on(fetchUserFx.doneData, (_, user) => user)
.on(userLoaded, (_, user) => user)Now everything related to the user lives in one domain:
- effects,
- events,
- stores.
3. Why a Domain is needed
| Goal | Description |
|---|---|
| Grouping logic | Everything related to one feature can be kept in one area. |
| Lifecycle management | A domain can be reset, cleared, or cloned entirely. |
| Error handling and logging | A domain can intercept errors from all of its effects. |
| SSR and isolation | You can create separate domain instances per user request (avoiding state conflicts). |
4. Error handling inside a Domain
A domain has built-in hooks, such as .onCreateEffect, .onCreateStore, .onCreateEvent.
You can use them to centrally log or handle events.
userDomain.onCreateEffect(effect => {
effect.fail.watch(({ error }) => {
console.error('Effect error:', error)
})
})This way, if an error occurs in any effect inside userDomain, it gets intercepted automatically.
5. Domain hierarchy
Domains can be nested inside each other:
const appDomain = createDomain('app')
const userDomain = appDomain.createDomain('user')
const authDomain = appDomain.createDomain('auth')This is useful for large applications:
appDomain- the root, global state;userDomain- user data;authDomain- authentication and tokens;cartDomain- the cart (in e-commerce);- and so on.
6. Resetting and clearing a Domain (lifecycle)
Effector lets you recreate a Domain (for example, on logout):
import { fork, allSettled } from 'effector'
const scope = fork({ values: { $user: null } })
await allSettled(fetchUserFx, { scope, params: 1 })This gives you the ability to:
- have separate state per client (SSR, multiple instances),
- clear all state in a domain when the user logs out.
7. Domain as a "feature module"
You can think of it this way:
userDomain
├── events/
│ └── userLoaded
├── stores/
│ └── $user
├── effects/
│ └── fetchUserFx
└── samples/
└── connect event → effectThis is essentially a mini-application inside the application. A domain describes "what" a specific part of the system does.
8. Difference from plain code without a Domain
| Without a Domain | With a Domain | |
|---|---|---|
| Creation | createStore(), createEvent() | domain.createStore(), domain.createEvent() |
| Isolation | Everything is global | All entities are grouped |
| Logging | Must be done manually | Can be centralized |
| Errors | Must be caught separately | Domain intercepts them |
| SSR | Must be cleared manually | The whole scope can be cloned |
SUMMARY
A domain is a container (or module) in Effector that holds all related state, events, and effects. It helps:
- structure the code,
- manage the store's lifecycle,
- centralize error handling,
- isolate state between users and requests.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.