# re-reselect, a cache of Reselect selectors so one argument stops evicting the next

> re-reselect is a thin wrapper around Reselect that keeps a cache of selector instances keyed by an argument of your choosing, so switching between arguments no longer throws away the previous memoized value. It also offers a structured variant and lets you swap the cache object for your own strategy. With Reselect v5 providing native memoization options, the library's role is now mostly about multi-key caches.

**toomuchdesign/re-reselect** — Enhance Reselect selectors with deeper memoization and cache management.

- Repository: https://github.com/toomuchdesign/re-reselect
- Stars: 1,092 · Forks: 46
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/toomuchdesign-re-reselect

## The problem: one argument evicts the next

The core complaint is about how a standard Reselect selector behaves when it is called with different arguments. Switching between different arguments using standard Reselect selectors causes cache invalidation, since the default Reselect cache has a limit of one. So if a selector is called with one argument, then another, then the first again, the third call recomputes because the second call replaced the only cache entry. The re-reselect solution is to forward different calls to different Reselect selectors stored in a cache, so computed and memoized values are retained. The selectors work as normal Reselect selectors, but they are able to determine when to create a new selector or query a cached one on the fly, depending on the supplied arguments. The project describes itself as a lightweight wrapper meant to enhance selectors with deeper memoization and cache management.

```js
getData(state, itemId, 'dataA');
getData(state, itemId, 'dataB');
getData(state, itemId, 'dataA');
```

## How a call resolves, step by step

The mechanics of a cached selector call are listed as four steps, and they are the whole design. First, evaluate the cacheKey for the current call by executing the keySelector. Second, retrieve from the cache the Reselect selector stored under the given cacheKey. Third, return the found selector, or create a new one if no selector was found. Fourth, call the returned selector with the provided arguments. The keySelector is a custom function that takes the same arguments as the selector itself and returns a cacheKey, and the cacheKey is by default a string or a number, though it can be anything depending on the chosen cache strategy. A unique persisting Reselect selector instance is stored in the cache for a given cacheKey, one to one. Replacing a selector with a cached selector is invisible to the consuming application since the API is the same.

```js
const getData = createCachedSelector(
  state => state,
  (state, itemId) => itemId,
  (state, itemId, dataType) => dataType,
  (state, itemId, dataType) => expensiveComputation(state, itemId, dataType)
)(
  (state, itemId, dataType) => dataType // Use dataType as cacheKey
);
```

## What it is for, and the alternatives it names

The listed use cases read like a checklist of selector problems. Retain a selector's cache when it is sequentially called with one or a few different arguments. Join similar selectors into one. Share selectors with props across multiple component instances. Instantiate selectors at runtime. And enhance Reselect with custom caching strategies. The documentation also names three alternative solutions and their costs, which is more useful than a claim of uniqueness. Declaring a different selector for each call is easy but does not scale. The selector factory approach suggested in the Reselect docs has a few downsides: it bloats your code by exposing both get selectors and makeGet selector factories, it needs you to import and call the factory instead of using the selector directly, and two different instances given the same arguments will individually store and recompute the same result. Wrapping the factory in a memoizer is what re-reselect itself does.

```
- Bloats your code by exposing both `get` selectors and `makeGet`
  selector factories
- Needs to import/call the selector factory instead of directly using
  the selector
```

## The structured variant, for when one key is not enough

Beyond the basic createCachedSelector, the API reference lists a createStructuredCachedSelector, and the reason it exists is the shape of the key. The basic version keys on a single value, which works when one argument identifies the computation. The structured variant exists for the case where you need more than one dimension, alongside examples for joining similar selectors, avoiding selector factories, caching API calls, programmatic keySelector composition and usage with Selectorator. The practical upshot is that a key which is not a single primitive is where the interesting configuration lives, and that is also where the cache strategy has to change, because the default key is a string or a number and anything else depends on the chosen strategy.

```
Join similar selectors
Avoid selector factories
Cache API calls
Programmatic keySelector composition
Usage with Selectorator
```

## The Reselect v5 question, asked honestly

The first paragraph of the project documentation addresses the elephant in the room. From Reselect v5, Reselect provides the ability to natively implement custom memoization and caching solutions via createSelector options, and most of the features re-reselect used to enable should now be natively available in Reselect. The project says re-reselect will try to support Reselect v5 and later for backward compatibility reasons. That is an unusually candid statement from a library, and it changes how you should evaluate the dependency. If your problem is single-argument memoization with a custom cache, the answer is now to use Reselect's own options and take one fewer dependency. If your problem is a multi-key cache of selector instances, which is a slightly different thing from a memoization cache because the selector itself is the cached artefact, then re-reselect still has a job. The peer dependency reflects this, requiring Reselect 5 or later.

```
`createSelector` options
```

## The package, and how it is built and tested

The package metadata is a well-organised TypeScript library. The version is 5.1.1, the licence is MIT, and the distribution ships a CommonJS build, an ES module build, a UMD browser build and the type declarations, with sideEffects set to false so a bundler can drop it when unused. The build script removes the dist directory and runs rollup with a bundled config. The test setup is unusual and worth noting: there is a separate bundle test suite with its own configs for the CommonJS, ES module and UMD outputs, and the prepare script runs a source check, the test suite, the build and then the bundle tests, so a published artefact has been verified in all three module formats rather than only from source. Formatting is prettier, typing is checked with tsc, releases go through changesets with a changelog generator, and the author is Andrea Carraro. The last push to the repository was on 2026-10-15 and the recent release is v5.1.1 from 2026-07-29.

```json
{
  "name": "re-reselect",
  "version": "5.1.1",
  "main": "dist/cjs/index.js",
  "module": "dist/es/index.js",
  "sideEffects": false,
  "peerDependencies": {
    "reselect": "^5.0.0"
  }
}
```

## Where it fits, and what to check first

The honest summary is that re-reselect is a small, focused tool for a specific cache shape, and the project tells you when you no longer need it. If your selectors are called with one argument, plain Reselect is enough. If they are called with several and you want the earlier results kept, re-reselect does the work with a familiar API. If you want a custom cache, Reselect v5 options may now cover it. The checks before adding the dependency are three. The first is the Reselect version, since the library will try to support v5 and later, and pinning an old Reselect buys you nothing that the native options do not now provide. The second is the key stability, because a key that changes on every call produces a cache that never hits and grows forever, and the library has no eviction policy of its own because the cache object is yours. The third is the shape of your usage, and the FAQ is a good way to answer it, since the examples cover joining selectors, avoiding factories, caching API calls, programmatic key composition and Selectorator, which between them cover most reasons people reach for this library.

```
lightweight wrapper around
```

## Conclusion

Adopt re-reselect if your selectors are called with several different arguments in sequence and the single-entry Reselect cache keeps throwing away work you want kept, and skip it if your selectors always take the same arguments, because a plain Reselect selector already handles that. Verify three things before you add it: whether Reselect v5 already covers your case with its own options, since the project says most features it used to provide are now native and it will try to support v5 and later for backward compatibility; which cache strategy you use, since the default key is a string or number and anything else needs a different cache object; and whether your key is actually stable, because a key that changes on every call gives you a cache that grows without ever hitting.

## FAQ

### What problem does re-reselect solve?

Switching between different arguments using standard Reselect selectors causes cache invalidation, because the default Reselect cache holds only one entry. re-reselect forwards different calls to different Reselect selectors stored in a cache, so computed and memoized values are retained rather than discarded.

### What is a keySelector and a cacheKey?

The keySelector is a custom function that takes the same arguments as the selector itself and returns a cacheKey. The cacheKey is the return value of that function, a string or a number by default, though it can be anything depending on the chosen cache strategy. A unique persisting Reselect selector instance is stored in the cache for each cacheKey.

### Is re-reselect still needed with Reselect v5?

The project says that from Reselect v5, Reselect can natively implement custom memoization and caching solutions through createSelector options, and that most features re-reselect used to enable should now be natively available. re-reselect will try to support Reselect v5 and later for backward compatibility reasons, and its peer dependency requires Reselect 5 or later.

### How do I install re-reselect?

With `npm install reselect` and `npm install re-reselect`, since Reselect is a peer dependency. The package is written in TypeScript and published with CommonJS, ES module and UMD builds along with type declarations.

## Sources

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

---

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