---
type: docs
order: 3
title: "Custom Stores"
permalink: docs/stores/
---

> This section concerns storing the internal application state, if you work with React/Redux, for example. If none of this rings a bell, you can safely skip this section.

By default, Uppy stores its internal state in an object.

If your app uses a state management library such as [Redux](https://redux.js.org), it can be useful to have Uppy store its state there instead—that way, you could write custom uploader UI components in the same way as the other components in the application.

Uppy comes with two state management solutions (stores):

 - `@uppy/store-default`, a simple object-based store.
 - `@uppy/store-redux`, a store that uses a key in a Redux store.

There are also some third-party stores:

 - [uppy-store-ngrx](https://github.com/rimlin/uppy-store-ngrx/), keeping Uppy state in a key in an [Ngrx](https://github.com/ngrx/platform) store for use with Angular.

## Using stores

To use a store, pass an instance to the [`store` option](/docs/uppy#store-defaultstore) in the Uppy constructor:

```js
const defaultStore = require('@uppy/store-default')

const uppy = Uppy({
  store: defaultStore()
})
```

### `DefaultStore`

Uppy uses the `DefaultStore`…by default! You do not need to do anything to use it.
It does not take any options.

### `ReduxStore`

The `ReduxStore` stores Uppy state on a key in an existing Redux store.
The `ReduxStore` dispatches `uppy/STATE_UPDATE` actions to update state.
When the state in Redux changes, it notifies Uppy.
This way, you get most of the benefits of Redux, including support for the Redux Devtools and time traveling!

To use the `ReduxStore`, add its reducer to the `uppy` key:

```js
const ReduxStore = require('@uppy/store-redux')
const reducer = combineReducers({
  ...reducers,
  uppy: ReduxStore.reducer
})
```

Then pass a Redux store instance to the Uppy constructor:

```js
const { createStore } = require('redux')
const ReduxStore = require('@uppy/store-redux')

const store = createStore(reducer)
const uppy = Uppy({
  store: ReduxStore({
    store: store // That's a lot of stores!
  })
})
```

#### `opts.store`

Pass a Redux store instance, from `Redux.createStore`.
This instance should have the Uppy reducer mounted somewhere already.

#### `opts.id`

By default, the `ReduxStore` assumes Uppy state is stored on a `state.uppy[id]` key.
`id` is randomly generated by the store constructor, but can be specified by passing an `id` option if it should be predictable.

```js
ReduxStore({
  store: store,
  id: 'avatarUpload'
})
```

#### `opts.selector`

If you'd rather not store the Uppy state under the `state.uppy` key at all, use the `selector` option to the `ReduxStore` constructor to tell it where to find state instead:

```js
const uppy = Uppy({
  store: ReduxStore({
    store: store,
    selector: state => state.pages.profile.uppy.avatarUpload
  })
})
```

If your app uses [`reselect`](https://npmjs.com/package/reselect), its selectors work very well with this!

## Implementing Stores

An Uppy store is an object with three methods.

 - `getState()` - Return the current state object.
 - `setState(patch)` - Merge the object `patch` into the current state.
 - `subscribe(listener)` - Call `listener` whenever the state changes.
   `listener` is a function that should receive three parameters:
   `(prevState, nextState, patch)`

   The `subscribe()` method should return a function that 'unsubscribes' (removes) the `listener`.

The default store implementation, for example, looks a bit like this:

```js
function defaultStore () {
  let state = {}
  const listeners = new Set()

  return {
    getState: () => state,
    setState: (patch) => {
      const prevState = state
      const nextState = Object.assign({}, prevState, patch)

      state = nextState

      listeners.forEach((listener) => {
        listener(prevState, nextState, patch)
      })
    },
    subscribe: (listener) => {
      listeners.add(listener)
      return () => listeners.remove(listener)
    }
  }
}
```

A pattern like this, where users can pass options via a function call if necessary, is recommended.

See the [./src/store](https://github.com/transloadit/uppy/tree/master/src/store) folder in the repository for more inspiration.
