Configuration

Overmind is based on a core concept of:

{ state, actions, effects }

This data structure is called the configuration of your application. If it is a simple application you might have a single configuration, but typically you will create multiple of them and use tools to merge them together into one big configuration. But before we look at the scalability of Overmind, let’s talk about file structure.

Domains

As your application grows you start to separate it into different domains. A domain might be closely related to a page in your application, or maybe it is strictly related to managing some piece of data. It does not matter. You define the domains of your application and they probably change over time as well. What matters in the context of Overmind though is that each of these domains will contain their own state, actions and effects. So imagine a file structure of:

overmind/
state.ts
actions.ts
effects.ts
index.ts

In this structure we are splitting up the different components of the configuration. This is a good first step. The index file acts as the file that brings the state, actions and effects together.

But if we want to split up into actual domains it would look more like this:

overmind/
posts/
state.ts
actions.ts
effects.ts
index.ts
admin/
state.ts
actions.ts
effects.ts
index.ts
index.ts

In this case each domain index file bring its own state, actions and effects together and the overmind/index file is responsible for bringing the whole configuration together.

The state file

You will typically define your state file by exporting a single constant named state.

overmind/posts/state.js
overmind/admin/state.js
overmind/posts/state.js
export const state = {
posts: []
}
overmind/admin/state.js
export const state: State = {
users: []
}

The actions file

The actions are exported individually by giving them a name and a definition.

overmind/posts/actions.js
overmind/admin/actions.js
overmind/posts/actions.js
export const getPosts = async () => {}
export const addNewPost = async () => {}
overmind/admin/actions.js
export const getUsers = async () => {}
export const changeUserAccess = async () => {}

The effects file

The effects are also exported individually where you would typically organize the methods in an object, but this could have been a class instance or just a plain function as well.

overmind/posts/effects.js
overmind/admin/effects.js
overmind/posts/effects.js
export const postsApi = {
getPostsFromServer() {}
}
overmind/admin/effects.js
export const adminApi = {
getUsersFromServer() {}
}

You might find it more useful to define a single effects file at the root of your application and rather create a file for each effect.

overmind/effects/index.js
overmind/effects/api.js
overmind/effects/index.js
import * as api from './api'
export {
api
}
overmind/effects/api.js
export const getUser = async () => {}
export const getPosts = async () => {}

Bring it together

Now let us export the state, actions and effects for each module and bring it all together into a namespaced configuration.

overmind/posts/index.js
overmind/admin/index.js
overmind/index.js
overmind/posts/index.js
import { state } from './state'
import * as actions from './actions'
import * as effects from './effects'
export {
state,
actions,
effects
}
overmind/admin/index.js
import { state } from './state'
import * as actions from './actions'
import * as effects from './effects'
export {
state,
actions,
effects
}
overmind/index.js
import { namespaced } from 'overmind/config'
import * as posts from './posts'
import * as admin from './admin'
export const config = namespaced({
posts,
admin
})

We used the namespaced function to put the state, actions and effects from each domain behind a key. In this case the key is the same as the name of the domain itself. This is an effective way to split up your app.

You can also combine this with the merge tool to have a top level domain.

overmind/index.js
overmind/index.js
import { merge, namespaced } from 'overmind/config'
import { state } from './state'
import * as posts from './posts'
import * as admin from './admin'
export const config = merge(
{
state
},
namespaced({
posts,
admin
})
)

Even though you split up into different domains each domain has access to the state of the whole application. This is an important feature of Overmind which allows you to scale up and explore the domains of the application without having to worry about isolation.