Redis driver: support ioredis v6
Problem
@verrou/core declares ioredis as an optional peer dependency with the range ^5.3.2. ioredis 6.0.0 was published on 2026-07-31 and is now the latest tag.
When a project has another dependency that requires ioredis 6 (for example @adonisjs/redis 10.0.1), pnpm installs two copies of ioredis: 6.0.0 for that dependency and a private 5.11.1 for verrou, because verrou's peer range rejects v6.
The two copies have different type identities. Passing the app's ioredis 6 client to redisStore({ connection }) then fails typecheck:
error TS2322: Type 'Redis<"legacy">' is not assignable to type 'Redis'.
Type 'import(".../ioredis@6.0.0/.../RedisOptions").RedisOptions' is not assignable to type 'import(".../ioredis@5.11.1/.../RedisOptions").RedisOptions'.
Type 'import(".../ioredis@6.0.0/.../ConnectorConstructor").default | undefined' is not assignable to type 'import(".../ioredis@5.11.1/.../ConnectorConstructor").default | undefined'.
In v6 the Redis class is generic: Redis<ReplyMapping extends "legacy" | "resp3" = "legacy">. In v5 it has no type parameter. That is why the message shows Redis<"legacy"> on one side and Redis on the other.
What ioredis 6 changes
From the ioredis changelog, 6.0.0 has one breaking-change entry:
ioredis now requires Node.js 20 or newer and uses RESP3 by default. Set protocol: 2 to retain the v5 wire protocol.
Reply shapes stay RESP2-compatible by default (replyMapping: "legacy"), so GET, SET, SETNX, DEL and Lua EVAL return the same values as in v5.
I compared the RedisCommander.d.ts typings of 5.11.1 and 6.0.0 for the five commands the driver calls in src/drivers/redis.ts:
| Call |
Used in |
Changed in v6 |
set(key, value, 'PX', ms, 'NX') |
save() |
No |
setnx(key, value) |
save() |
No |
eval(script, numkeys, ...args) |
delete(), extend() |
No |
del(key) |
forceDelete() |
No |
get(key) |
exists() |
No |
Redis and Cluster are still exported the same way from ioredis, and the package is still CJS only with no exports map.
Proposed fix
Two parts.
-
Widen the peer range in packages/verrou/package.json to "ioredis": "^5.3.2 || ^6.0.0". This stops package managers from installing a second copy and fixes the error above with no code change.
-
Decouple the connection option from the ioredis class identity. Today RedisStoreOptions.connection is typed as import type { Redis } from 'ioredis'. A minimal structural interface with the five methods the driver uses would accept a v5 client, a v6 client, a Redis<"resp3"> client, and a Cluster client, and would not break again the next time ioredis changes the class shape.
Part 1 alone is enough to fix the immediate problem. Part 2 removes the class of problem.
Verification
I checked part 1 in a local clone. With ioredis bumped to 6.0.0 in devDependencies and the peer range widened, and no change to src/:
pnpm -r build: passes
pnpm typecheck (root and packages/verrou): 0 errors
pnpm -C packages/verrou lint: 0 errors
tests/drivers/redis.spec.ts against a local Redis 8: 26 tests pass
I then reverted the devDependency to 5.8.2 with the widened peer range in place. Typecheck and the same 26 tests pass again.
Notes
- ioredis 6 needs Node 20+. The repo
engines field says >=18.16.0. That does not need to change for the peer range to work, but it may be worth a note in the docs.
- The
Redis page in docs/content/docs/drivers.md and playground/package.json still pin ^5.8.2.
I am happy to open a PR for either or both parts.
Redis driver: support ioredis v6
Problem
@verrou/coredeclaresioredisas an optional peer dependency with the range^5.3.2. ioredis 6.0.0 was published on 2026-07-31 and is now thelatesttag.When a project has another dependency that requires ioredis 6 (for example
@adonisjs/redis10.0.1), pnpm installs two copies of ioredis: 6.0.0 for that dependency and a private 5.11.1 for verrou, because verrou's peer range rejects v6.The two copies have different type identities. Passing the app's ioredis 6 client to
redisStore({ connection })then fails typecheck:In v6 the
Redisclass is generic:Redis<ReplyMapping extends "legacy" | "resp3" = "legacy">. In v5 it has no type parameter. That is why the message showsRedis<"legacy">on one side andRedison the other.What ioredis 6 changes
From the ioredis changelog, 6.0.0 has one breaking-change entry:
Reply shapes stay RESP2-compatible by default (
replyMapping: "legacy"), soGET,SET,SETNX,DELand LuaEVALreturn the same values as in v5.I compared the
RedisCommander.d.tstypings of 5.11.1 and 6.0.0 for the five commands the driver calls insrc/drivers/redis.ts:set(key, value, 'PX', ms, 'NX')save()setnx(key, value)save()eval(script, numkeys, ...args)delete(),extend()del(key)forceDelete()get(key)exists()RedisandClusterare still exported the same way fromioredis, and the package is still CJS only with noexportsmap.Proposed fix
Two parts.
Widen the peer range in
packages/verrou/package.jsonto"ioredis": "^5.3.2 || ^6.0.0". This stops package managers from installing a second copy and fixes the error above with no code change.Decouple the
connectionoption from the ioredis class identity. TodayRedisStoreOptions.connectionis typed asimport type { Redis } from 'ioredis'. A minimal structural interface with the five methods the driver uses would accept a v5 client, a v6 client, aRedis<"resp3">client, and aClusterclient, and would not break again the next time ioredis changes the class shape.Part 1 alone is enough to fix the immediate problem. Part 2 removes the class of problem.
Verification
I checked part 1 in a local clone. With
ioredisbumped to 6.0.0 indevDependenciesand the peer range widened, and no change tosrc/:pnpm -r build: passespnpm typecheck(root andpackages/verrou): 0 errorspnpm -C packages/verrou lint: 0 errorstests/drivers/redis.spec.tsagainst a local Redis 8: 26 tests passI then reverted the devDependency to 5.8.2 with the widened peer range in place. Typecheck and the same 26 tests pass again.
Notes
enginesfield says>=18.16.0. That does not need to change for the peer range to work, but it may be worth a note in the docs.Redispage indocs/content/docs/drivers.mdandplayground/package.jsonstill pin^5.8.2.I am happy to open a PR for either or both parts.