# redux-box: a batteries-included container that shortens Redux setup

> redux-box wraps Redux and Redux-Saga behind createModule and createStore so a state container can be declared in a dozen lines instead of a folder of action types, reducers and sagas, with Immer making the mutations look mutable while keeping them immutable underneath. It is MIT licensed, but the newest release tag is a 2.0.0 beta from 2019.

**anish000kumar/redux-box** — Modular and easy-to-grasp redux  based state management, with least boilerplate

- Repository: https://github.com/anish000kumar/redux-box
- Stars: 703 · Forks: 21
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/anish000kumar-redux-box

## A whole store in two short files

redux-box describes itself as a modular, batteries-included container for Redux and Redux-Saga applications, with the pitch being less boilerplate, cleaner reducers and sagas already wired up.

The demonstration is short enough to be the whole argument. A counter module is one file:

```js
// store/counter.js
import { createModule } from 'redux-box';

export default createModule({
  state: { count: 0 },
  mutations: {
    INCREMENT: state => { state.count += 1; },
  },
});
```

And the store is another:

```js
// store/index.js
import { createStore } from 'redux-box';
import counter from './counter';

export default createStore({ counter });
```

That is a complete Redux store, as the readme says. In a conventional setup, the same counter would need an action type constant, an action creator, a reducer with a switch statement, and a separate registration step in the root reducer. Here, the mutation name and the state shape sit in the same object, and the store is assembled by listing the modules.

The module is the unit of organisation, and the name is not decorative. Each module owns its own state slice, its own mutations and, presumably, its own sagas, and the modules are what you pass to createStore. That is a small API surface, and it is the reason the boilerplate claim holds up.

The two functions are the entire public contract that a user needs to start with, and everything else in the package is convention.

## Immer makes the mutations look mutable on purpose

The one piece of behaviour in the readme that needs explaining is that the mutations look mutable but are made immutable under the hood by Immer.

In plain Redux, a reducer must not modify the state it receives. The idiomatic form is to return a new object, which for a nested structure means spreading at every level. That is correct but verbose, and it is where a lot of Redux boilerplate comes from.

The redux-box example sidesteps it. The mutation reads state.count += 1, which is a direct assignment, and Immer produces the copy behind the scenes. The reducer body looks like ordinary imperative code, and the immutability guarantee is preserved.

This is a real ergonomic win, and it is also a real learning curve. A developer who has internalised that reducers must not mutate will read state.count += 1 and assume it is a bug, and a developer who has not internalised it will be confused when the framework freezes an object and throws on a later accidental mutation. The documentation and the guide would need to make the mechanism explicit for a team picking this up.

The dependency list backs the story. Immer at 10.1.1 or later, redux 5.0.1, react-redux 9.1.2, redux-saga 1.3.0, reselect 5.1.1 for memoised selectors, and regenerator-runtime for the generator transforms sagas rely on. Those are the standard Redux stack pieces, which is what batteries-included means here: it is not a different state model, it is the same model with the wiring done for you.

## The npm package and the repository have drifted apart

The release history is the thing to check before you depend on this, because it tells you two different stories.

The most recent release tags are 2.0.0-beta.1 from 2019-08-28 and 1.0.1, titled First Release, from 2018-01-13. A 2.0.0 beta from 2019 means the 2.x line was never tagged as final, and the 1.0.1 line is eight years older than the last commit.

Meanwhile the package metadata says the version is 2.1.0, which is higher than either tag. So the published package on npm is at 2.1.0, the git tags stop at a 2019 beta, and the repository is not archived with the last push on 2026-05-09, five months before the current date.

That combination is not necessarily alarming. A project can keep committing to master without cutting a release, and the version in package.json can be ahead of the tags. But it does mean there is no tag you can pin to and be sure matches what npm serves, and no changelog entry to explain what changed between the beta and 2.1.0.

The repository is otherwise conventionally set up for a library of this size. The source is in src/, the built output in dist/, tests/ with jest.config.js, examples/ with a crud-rest example and a trello-graphql example, docs/ for the documentation site, a babel.config.js and two tsconfig files for the build, a.husky/ directory for commit hooks, and both a package-lock.json and a yarn.lock.

The licence is MIT, with the LICENSE file at the root and the author named as Anish Kumar.

## TypeScript in, JavaScript out, and two build passes

The build is worth a look because it explains a few things about the package.

The source is TypeScript, with the primary language recorded as TypeScript, and the build script runs Babel over the source and then the TypeScript compiler:

```bash
    "build": "babel src --out-dir dist --extensions .ts && tsc -p tsconfig.build.json",
```

So Babel handles the transpilation of the TypeScript sources into the dist directory, and tsc runs separately against tsconfig.build.json to produce the type declarations. The package points main at dist/index.js and types at dist/index.d.ts, and the files list in the metadata covers the dist directory, so the published tarball is just the built output.

The type check has its own script, tsc --noEmit against tsconfig.json, separate from the build, so a type error is caught without emitting anything.

The test setup is jest with coverage collected from the TypeScript sources under src, and a second variant pipes the lcov output to Coveralls. The testing library packages in the dev dependencies, @testing-library/react and @testing-library/dom, plus jest-dom, say that the tests render components rather than only calling functions.

The documentation is generated rather than written by hand. A script runs vuepress-jsdoc over the source directory, producing the API pages into a docs folder and excluding getReducer.js and composeEnhancers.js, which are the two internals the author did not want in the public API. There are separate dev and build commands for the VuePress site, and the readme links to the published version at the GitHub Pages site.

The type definitions are therefore part of the published package, which matters for a state library: the whole value of the library is a small typed API, and the types ship with it.

## Where redux-box is the wrong choice

There is a clear case against it, and the case is not about the quality of the code.

The first is the alternative that already exists. Redux Toolkit is the standard answer to the same problem, and it is a widely used answer to the same problem. Choosing redux-box over Redux Toolkit means choosing a 2019 beta from a single author over an actively maintained official library, for a similar reduction in boilerplate. 

The second is the framework lock-in angle. Redux and Redux-Saga are not the default choices any more. A new React application might use a server state library for fetching and caching and a small amount of local component state, in which case a Redux container is solving a problem the application does not have. A React Native or Vue application, both of which appear in the package keywords alongside react-native and vue, faces the same question.

The third is the maintenance signal, stated earlier and worth repeating here as a decision factor. The last push was on 2026-05-09, the newest tag is a 2019 beta, and the package version in the metadata has moved past both. For a library that sits underneath every screen of an application, that is thin.

What remains in favour is a genuine design idea. A module-based container where the state shape, the mutations and the sagas live together, with Immer making the mutations read like ordinary code, is a good API. It is also one that Redux Toolkit has largely absorbed, which is why the choice comes down to whether you want the batteries-included convenience of a small independent package or the maintenance backing of the official one.

## Conclusion

redux-box suits a team starting a new React or React Native application that wants Redux and Redux-Saga wired up in one file per module rather than four, and that values the Immer style of writing mutations. It does not suit a team that needs a maintained, battle-tested state library today, since the newest tag is a 2019 beta even though the last push was on 2026-05-09, and it does not replace Redux Toolkit, which solves the same problem with a larger ecosystem. Before adopting it, check the npm dist tag for the version you would actually install, and read the Immer behaviour in the documentation, because the mutable-looking reducers are the part that surprises newcomers.

## FAQ

### What is redux-box?

It is a modular, batteries-included container for Redux and Redux-Saga applications, aimed at less boilerplate and cleaner reducers, with sagas, devtools and middleware wired up. The public API for starting is createModule for each state module and createStore to assemble them.

### How do I install redux-box?

With npm install redux-box, or with yarn add redux-box. The package is published to npm as redux-box and ships TypeScript declarations alongside the built JavaScript.

### Do redux-box mutations really mutate the state?

No. The mutations look mutable, for example state.count += 1, but they are made immutable under the hood by Immer. The readme describes this as the reason the reducers can be written in a clean, direct style.

### What version of redux-box is current?

The package metadata declares version 2.1.0, while the newest release tags are 2.0.0-beta.1 from 2019-08-28 and 1.0.1 from 2018-01-13. The repository is not archived and the last push was on 2026-05-09.

### What testing and documentation tooling does redux-box use?

Jest with coverage collected from the TypeScript sources and a Coveralls variant, testing library packages for rendering components, and VuePress with jsdoc to generate the API documentation from the source. The build itself runs Babel over src into dist and then tsc against tsconfig.build.json for the declarations.

## Sources

- [anish000kumar/redux-box on GitHub](https://github.com/anish000kumar/redux-box)
- [Issues](https://github.com/anish000kumar/redux-box/issues)
- [License: MIT](https://github.com/anish000kumar/redux-box/blob/master/LICENSE)
- [README](https://github.com/anish000kumar/redux-box/blob/master/README.md)
- [Releases](https://github.com/anish000kumar/redux-box/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/anish000kumar-redux-box
