|
| 1 | +# v5 to v6 migration guide |
| 2 | + |
| 3 | +## RESP3 is now the default protocol |
| 4 | + |
| 5 | +In v5, Node-Redis defaulted to `RESP: 2` unless you explicitly configured `RESP: 3`. |
| 6 | +In v6, the default is now `RESP: 3`. |
| 7 | + |
| 8 | +RESP3 introduces a bunch of “on the wire” formats that replace RESP2 workarounds. |
| 9 | +Node-Redis already maps most of the RESP2 workarounds to the proper javascript type, but there are some commands that were missed. |
| 10 | +Those are now aligned to return the proper types. For more details on protocol type mapping, see [RESP type mapping](./RESP.md). |
| 11 | + |
| 12 | + |
| 13 | +## Default behavior changes (v5 default -> v6 default) |
| 14 | + |
| 15 | + - `GEOSEARCH_WITH`, `GEORADIUS_WITH`, `GEORADIUS_RO_WITH`, `GEORADIUSBYMEMBER_WITH`, `GEORADIUSBYMEMBER_RO_WITH` - `distance`, `coordinates.longitude`, and `coordinates.latitude` are now `number` (previously `string`). |
| 16 | + |
| 17 | +<!--V5: |
| 18 | +
|
| 19 | +```ts |
| 20 | +export interface GeoReplyWithMember { |
| 21 | + member: string; |
| 22 | + distance?: string; |
| 23 | + hash?: number; |
| 24 | + coordinates?: { |
| 25 | + longitude: string; |
| 26 | + latitude: string; |
| 27 | + }; |
| 28 | +} |
| 29 | +``` |
| 30 | +
|
| 31 | +V6: |
| 32 | +
|
| 33 | +```ts |
| 34 | +export interface GeoReplyWithMember { |
| 35 | + member: string; |
| 36 | + distance?: number; |
| 37 | + hash?: number; |
| 38 | + coordinates?: { |
| 39 | + longitude: number; |
| 40 | + latitude: number; |
| 41 | + }; |
| 42 | +} |
| 43 | +```--> |
| 44 | + |
| 45 | + - `CF.INSERTNX` changed from `Array<boolean>` to `Array<number>`. |
| 46 | + |
| 47 | + |
| 48 | +## Stabilized APIs |
| 49 | +In v5, some command transforms were unstable under RESP3. In v6, those commands are stabilized and normalized: |
| 50 | + |
| 51 | +| Package | Command | Return type change | Notes | |
| 52 | +|---|---|---|---| |
| 53 | +| `@redis/client` | `HOTKEYS GET` | `ReplyUnion -> HotkeysGetReply \| null` | RESP3 reply now normalized to stable structured output. | |
| 54 | +| `@redis/client` | `MODULE LIST` | `ModuleListReply -> ModuleListReply` | Static type is unchanged; RESP3 map-like payload is normalized to `{ name, ver }` entries. | |
| 55 | +| `@redis/client` | `XREAD` | `ReplyUnion -> StreamsMessagesReply \| null` | RESP3 reply is normalized to v4/v5-compatible stream list shape. | |
| 56 | +| `@redis/client` | `XREADGROUP` | `ReplyUnion -> StreamsMessagesReply \| null` | RESP3 reply is normalized to v4/v5-compatible stream list shape. | |
| 57 | +| `@redis/search` | `FT.AGGREGATE` | `ReplyUnion -> AggregateReply` | RESP3 map/array variants normalized to aggregate reply shape. | |
| 58 | +| `@redis/search` | `FT.AGGREGATE WITHCURSOR` | `ReplyUnion -> AggregateWithCursorReply` | Cursor + results are normalized for RESP3. | |
| 59 | +| `@redis/search` | `FT.CURSOR READ` | `ReplyUnion -> AggregateWithCursorReply` | Inherits `FT.AGGREGATE WITHCURSOR` transform changes. | |
| 60 | +| `@redis/search` | `FT.SEARCH` | `ReplyUnion -> SearchReply` | RESP3 map-like payload normalized to `{ total, documents }`. | |
| 61 | +| `@redis/search` | `FT.SEARCH NOCONTENT` | `ReplyUnion -> SearchNoContentReply` | RESP3 normalized through `FT.SEARCH` then projected to ids. | |
| 62 | +| `@redis/search` | `FT.SPELLCHECK` | `ReplyUnion -> SpellCheckReply` | RESP3 result/suggestion map variants normalized. | |
| 63 | +| `@redis/search` | `FT.HYBRID` | `ReplyUnion -> HybridSearchResult` | RESP3 map-like payload normalized to hybrid result object. | |
| 64 | +| `@redis/search` | `FT.PROFILE SEARCH` | `ReplyUnion -> ProfileReplyResp2` | RESP3 profile/results wrappers normalized (Redis 7.4/8 layouts). | |
| 65 | +| `@redis/search` | `FT.PROFILE AGGREGATE` | `ReplyUnion -> ProfileReplyResp2` | RESP3 profile/results wrappers normalized (Redis 7.4/8 layouts). | |
| 66 | +| `@redis/search` | `FT.CONFIG GET` | `Record<string, string \| null> -> Record<string, string \| null>` | Static type is unchanged; map-like RESP3 payload is now normalized correctly. | |
| 67 | +| `@redis/time-series` | `TS.INFO` | `ReplyUnion -> InfoReply` | RESP3 map/array variants normalized to `InfoReply`. | |
| 68 | +| `@redis/time-series` | `TS.INFO DEBUG` | `ReplyUnion -> InfoDebugReply` | RESP3 `keySelfName`/`chunks` payload normalized. | |
| 69 | +| `@redis/time-series` | `TS.MRANGE GROUPBY` | `{ sources: Array<string>; samples: Array<{ timestamp: number; value: number }> } -> { samples: Array<{ timestamp: number; value: number }> }` | `sources` removed from RESP3 grouped reply. | |
| 70 | +| `@redis/time-series` | `TS.MREVRANGE GROUPBY` | `{ sources: Array<string>; samples: Array<{ timestamp: number; value: number }> } -> { samples: Array<{ timestamp: number; value: number }> }` | Inherits `TS.MRANGE GROUPBY` transform changes. | |
| 71 | +| `@redis/time-series` | `TS.MRANGE SELECTED_LABELS` | `Record<string, { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }> -> Record<string, { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }>` | Static type is unchanged; tuple extraction fixed for RESP3 selected-labels payload. | |
| 72 | +| `@redis/time-series` | `TS.MREVRANGE SELECTED_LABELS` | `Record<string, { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }> -> Record<string, { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }>` | Inherits `TS.MRANGE SELECTED_LABELS` transform changes. | |
| 73 | +| `@redis/time-series` | `TS.MRANGE SELECTED_LABELS GROUPBY` | `{ labels: Record<string, string \| null>; sources: Array<string>; samples: Array<{ timestamp: number; value: number }> } -> { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }` | `sources` removed from RESP3 selected-labels grouped reply. | |
| 74 | +| `@redis/time-series` | `TS.MREVRANGE SELECTED_LABELS GROUPBY` | `{ labels: Record<string, string \| null>; sources: Array<string>; samples: Array<{ timestamp: number; value: number }> } -> { labels: Record<string, string \| null>; samples: Array<{ timestamp: number; value: number }> }` | Inherits `TS.MRANGE SELECTED_LABELS GROUPBY` transform changes. | |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +If you need to preserve v5 default behavior while migrating, pin RESP2 explicitly: |
| 79 | + |
| 80 | +```javascript |
| 81 | +// Single node |
| 82 | +const client = createClient({ RESP: 2 }); |
| 83 | + |
| 84 | +// Cluster |
| 85 | +const cluster = createCluster({ RESP: 2, ...}); |
| 86 | + |
| 87 | +// Sentinel |
| 88 | +const sentinel = createSentinel({ RESP: 2, ... }); |
| 89 | + |
| 90 | +// Pool |
| 91 | +const pool = createClientPool({ RESP: 2 }); |
| 92 | +``` |
0 commit comments