diff --git a/packages/client/lib/client/parser.ts b/packages/client/lib/client/parser.ts
index 475ac0538b0..25b5e008310 100644
--- a/packages/client/lib/client/parser.ts
+++ b/packages/client/lib/client/parser.ts
@@ -1,4 +1,4 @@
-import { RedisArgument, RespVersions } from "../..";
+import { RedisArgument, RespVersions } from "../RESP/types";
 import { RedisVariadicArgument } from "../commands/generic-transformers";
 
 export interface CommandParser {
@@ -8,9 +8,10 @@ export interface CommandParser {
   respVersion: RespVersions;
   preserve: unknown;
   cachable: boolean;
-  
+
   push: (arg: RedisArgument) => unknown;
   pushVariadic: (vals: RedisVariadicArgument) => unknown;
+  pushVariadicWithLength: (vals: RedisVariadicArgument) => unknown;
   pushVariadicNumber: (vals: number | Array<number>) => unknown;
   pushKey: (key: RedisArgument) => unknown; // normal push of keys
   pushKeys: (keys: RedisVariadicArgument) => unknown; // push multiple keys at a time
@@ -68,6 +69,15 @@ export class BasicCommandParser implements CommandParser {
     }
   }
 
+  pushVariadicWithLength(vals: RedisVariadicArgument) {
+    if (Array.isArray(vals)) {
+      this.#redisArgs.push(vals.length.toString());
+    } else {
+      this.#redisArgs.push('1');
+    }
+    this.pushVariadic(vals);
+  }
+
   pushVariadicNumber(vals: number | number[]) {
     if (Array.isArray(vals)) {
       for (const val of vals) {
@@ -109,4 +119,4 @@ export class BasicCommandParser implements CommandParser {
   setCachable() {
     this.#cachable = true;
   };
-}
\ No newline at end of file
+}
diff --git a/packages/client/lib/commands/ACL_CAT.spec.ts b/packages/client/lib/commands/ACL_CAT.spec.ts
index 2ce9d7db922..09d5ecade5a 100644
--- a/packages/client/lib/commands/ACL_CAT.spec.ts
+++ b/packages/client/lib/commands/ACL_CAT.spec.ts
@@ -1,5 +1,6 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import ACL_CAT from './ACL_CAT';
 
 describe('ACL CAT', () => {
@@ -8,14 +9,14 @@ describe('ACL CAT', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ACL_CAT.transformArguments(),
+        parseArgs(ACL_CAT),
         ['ACL', 'CAT']
       );
     });
 
     it('with categoryName', () => {
       assert.deepEqual(
-        ACL_CAT.transformArguments('dangerous'),
+        parseArgs(ACL_CAT, 'dangerous'),
         ['ACL', 'CAT', 'dangerous']
       );
     });
diff --git a/packages/client/lib/commands/ACL_CAT.ts b/packages/client/lib/commands/ACL_CAT.ts
index dd4762239a7..b0e326d98c5 100644
--- a/packages/client/lib/commands/ACL_CAT.ts
+++ b/packages/client/lib/commands/ACL_CAT.ts
@@ -1,16 +1,15 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(categoryName?: RedisArgument) {
-    const args: Array<RedisArgument> = ['ACL', 'CAT'];
-
+  parseCommand(parser: CommandParser, categoryName?: RedisArgument) {
+    parser.pushVariadic(['ACL', 'CAT']);
     if (categoryName) {
-      args.push(categoryName);
+      parser.push(categoryName);
     }
-
-    return args;
   },
+  transformArguments(categoryName?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_DELUSER.spec.ts b/packages/client/lib/commands/ACL_DELUSER.spec.ts
index d6acbb22230..45fa3af9fc7 100644
--- a/packages/client/lib/commands/ACL_DELUSER.spec.ts
+++ b/packages/client/lib/commands/ACL_DELUSER.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_DELUSER from './ACL_DELUSER';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL DELUSER', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -8,14 +9,14 @@ describe('ACL DELUSER', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ACL_DELUSER.transformArguments('username'),
+        parseArgs(ACL_DELUSER, 'username'),
         ['ACL', 'DELUSER', 'username']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ACL_DELUSER.transformArguments(['1', '2']),
+        parseArgs(ACL_DELUSER, ['1', '2']),
         ['ACL', 'DELUSER', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/ACL_DELUSER.ts b/packages/client/lib/commands/ACL_DELUSER.ts
index c0f8e15d672..101bb4fbb59 100644
--- a/packages/client/lib/commands/ACL_DELUSER.ts
+++ b/packages/client/lib/commands/ACL_DELUSER.ts
@@ -1,11 +1,14 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(username: RedisVariadicArgument) {
-    return pushVariadicArguments(['ACL', 'DELUSER'], username);
+  parseCommand(parser: CommandParser, username: RedisVariadicArgument) {
+    parser.pushVariadic(['ACL', 'DELUSER']);
+    parser.pushVariadic(username);
   },
+  transformArguments(username: RedisVariadicArgument) { return []; },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_DRYRUN.spec.ts b/packages/client/lib/commands/ACL_DRYRUN.spec.ts
index 519092e0114..38a4def8361 100644
--- a/packages/client/lib/commands/ACL_DRYRUN.spec.ts
+++ b/packages/client/lib/commands/ACL_DRYRUN.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_DRYRUN from './ACL_DRYRUN';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL DRYRUN', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_DRYRUN.transformArguments('default', ['GET', 'key']),
+      parseArgs(ACL_DRYRUN, 'default', ['GET', 'key']),
       ['ACL', 'DRYRUN', 'default', 'GET', 'key']
     );
   });
diff --git a/packages/client/lib/commands/ACL_DRYRUN.ts b/packages/client/lib/commands/ACL_DRYRUN.ts
index 257f0fe61e2..a4685373293 100644
--- a/packages/client/lib/commands/ACL_DRYRUN.ts
+++ b/packages/client/lib/commands/ACL_DRYRUN.ts
@@ -1,16 +1,13 @@
 import { RedisArgument, SimpleStringReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(username: RedisArgument, command: Array<RedisArgument>) {
-    return [
-      'ACL',
-      'DRYRUN',
-      username,
-      ...command
-    ];
+  parseCommand(parser: CommandParser, username: RedisArgument, command: Array<RedisArgument>) {
+    parser.pushVariadic(['ACL', 'DRYRUN', username, ...command]);
   },
+  transformArguments(username: RedisArgument, command: Array<RedisArgument>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'> | BlobStringReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/ACL_GENPASS.spec.ts b/packages/client/lib/commands/ACL_GENPASS.spec.ts
index 44c1e167eb7..35e161f424f 100644
--- a/packages/client/lib/commands/ACL_GENPASS.spec.ts
+++ b/packages/client/lib/commands/ACL_GENPASS.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_GENPASS from './ACL_GENPASS';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL GENPASS', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -8,14 +9,14 @@ describe('ACL GENPASS', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ACL_GENPASS.transformArguments(),
+        parseArgs(ACL_GENPASS),
         ['ACL', 'GENPASS']
       );
     });
 
     it('with bits', () => {
       assert.deepEqual(
-        ACL_GENPASS.transformArguments(128),
+        parseArgs(ACL_GENPASS, 128),
         ['ACL', 'GENPASS', '128']
       );
     });
diff --git a/packages/client/lib/commands/ACL_GENPASS.ts b/packages/client/lib/commands/ACL_GENPASS.ts
index be89ff90a9a..df92a8f98dc 100644
--- a/packages/client/lib/commands/ACL_GENPASS.ts
+++ b/packages/client/lib/commands/ACL_GENPASS.ts
@@ -1,17 +1,16 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(bits?: number) {
-    const args = ['ACL', 'GENPASS'];
-
+  parseCommand(parser: CommandParser, bits?: number) {
+    parser.pushVariadic(['ACL', 'GENPASS']);
     if (bits) {
-      args.push(bits.toString());
+      parser.push(bits.toString());
     }
-
-    return args;
   },
+  transformArguments(bits?: number) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/ACL_GETUSER.spec.ts b/packages/client/lib/commands/ACL_GETUSER.spec.ts
index 47351571127..83776a3473a 100644
--- a/packages/client/lib/commands/ACL_GETUSER.spec.ts
+++ b/packages/client/lib/commands/ACL_GETUSER.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_GETUSER from './ACL_GETUSER';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL GETUSER', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_GETUSER.transformArguments('username'),
+      parseArgs(ACL_GETUSER, 'username'),
       ['ACL', 'GETUSER', 'username']
     );
   });
diff --git a/packages/client/lib/commands/ACL_GETUSER.ts b/packages/client/lib/commands/ACL_GETUSER.ts
index cbbf48a4c69..e41088c29a1 100644
--- a/packages/client/lib/commands/ACL_GETUSER.ts
+++ b/packages/client/lib/commands/ACL_GETUSER.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesToMapReply, BlobStringReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type AclUser = TuplesToMapReply<[
   [BlobStringReply<'flags'>, ArrayReply<BlobStringReply>],
@@ -19,9 +20,10 @@ type AclUser = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(username: RedisArgument) {
-    return ['ACL', 'GETUSER', username];
+  parseCommand(parser: CommandParser, username: RedisArgument) {
+    parser.pushVariadic(['ACL', 'GETUSER', username]);
   },
+  transformArguments(username: RedisArgument) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<AclUser>>) => ({
       flags: reply[1],
diff --git a/packages/client/lib/commands/ACL_LIST.spec.ts b/packages/client/lib/commands/ACL_LIST.spec.ts
index b188cae30b0..0f67aaa53e9 100644
--- a/packages/client/lib/commands/ACL_LIST.spec.ts
+++ b/packages/client/lib/commands/ACL_LIST.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_LIST from './ACL_LIST';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL LIST', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_LIST.transformArguments(),
+      parseArgs(ACL_LIST),
       ['ACL', 'LIST']
     );
   });
diff --git a/packages/client/lib/commands/ACL_LIST.ts b/packages/client/lib/commands/ACL_LIST.ts
index 1a831a4987c..7e14298263c 100644
--- a/packages/client/lib/commands/ACL_LIST.ts
+++ b/packages/client/lib/commands/ACL_LIST.ts
@@ -1,10 +1,12 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ACL', 'LIST'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'LIST']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_LOAD.spec.ts b/packages/client/lib/commands/ACL_LOAD.spec.ts
index 68552164ce0..a41ce45e8a6 100644
--- a/packages/client/lib/commands/ACL_LOAD.spec.ts
+++ b/packages/client/lib/commands/ACL_LOAD.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import ACL_LOAD from './ACL_LOAD';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL LOAD', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_LOAD.transformArguments(),
+      parseArgs(ACL_LOAD),
       ['ACL', 'LOAD']
     );
   });
diff --git a/packages/client/lib/commands/ACL_LOAD.ts b/packages/client/lib/commands/ACL_LOAD.ts
index 39587829b17..0aa6b698d4c 100644
--- a/packages/client/lib/commands/ACL_LOAD.ts
+++ b/packages/client/lib/commands/ACL_LOAD.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ACL', 'LOAD'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'LOAD']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_LOG.spec.ts b/packages/client/lib/commands/ACL_LOG.spec.ts
index b85a7076f4a..7da61faca37 100644
--- a/packages/client/lib/commands/ACL_LOG.spec.ts
+++ b/packages/client/lib/commands/ACL_LOG.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_LOG from './ACL_LOG';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL LOG', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -8,14 +9,14 @@ describe('ACL LOG', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ACL_LOG.transformArguments(),
+        parseArgs(ACL_LOG),
         ['ACL', 'LOG']
       );
     });
 
     it('with count', () => {
       assert.deepEqual(
-        ACL_LOG.transformArguments(10),
+        parseArgs(ACL_LOG, 10),
         ['ACL', 'LOG', '10']
       );
     });
diff --git a/packages/client/lib/commands/ACL_LOG.ts b/packages/client/lib/commands/ACL_LOG.ts
index fab870f27c3..a1fde4b1939 100644
--- a/packages/client/lib/commands/ACL_LOG.ts
+++ b/packages/client/lib/commands/ACL_LOG.ts
@@ -1,4 +1,5 @@
 import { ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, DoubleReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type AclLogReply = ArrayReply<TuplesToMapReply<[
   [BlobStringReply<'count'>, NumberReply],
@@ -19,15 +20,13 @@ export type AclLogReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(count?: number) {
-    const args = ['ACL', 'LOG'];
-
-    if (count !== undefined) {
-      args.push(count.toString());
+  parseCommand(parser: CommandParser, count?: number) {
+    parser.pushVariadic(['ACL', 'LOG']);
+    if (count != undefined) {
+      parser.push(count.toString());
     }
-
-    return args;
   },
+  transformArguments(count?: number) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<AclLogReply>>) => {
       return reply.map(item => {
diff --git a/packages/client/lib/commands/ACL_LOG_RESET.spec.ts b/packages/client/lib/commands/ACL_LOG_RESET.spec.ts
index 8849440c1a6..62d193a132d 100644
--- a/packages/client/lib/commands/ACL_LOG_RESET.spec.ts
+++ b/packages/client/lib/commands/ACL_LOG_RESET.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ACL_LOG_RESET from './ACL_LOG_RESET';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL LOG RESET', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_LOG_RESET.transformArguments(),
+      parseArgs(ACL_LOG_RESET),
       ['ACL', 'LOG', 'RESET']
     );
   });
diff --git a/packages/client/lib/commands/ACL_LOG_RESET.ts b/packages/client/lib/commands/ACL_LOG_RESET.ts
index 91d58d538e9..738207e9273 100644
--- a/packages/client/lib/commands/ACL_LOG_RESET.ts
+++ b/packages/client/lib/commands/ACL_LOG_RESET.ts
@@ -1,11 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ACL_LOG from './ACL_LOG';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: ACL_LOG.IS_READ_ONLY,
-  transformArguments() {
-    return ['ACL', 'LOG', 'RESET'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'LOG', 'RESET']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_SAVE.spec.ts b/packages/client/lib/commands/ACL_SAVE.spec.ts
index 1fe402867e7..98f7c9f183d 100644
--- a/packages/client/lib/commands/ACL_SAVE.spec.ts
+++ b/packages/client/lib/commands/ACL_SAVE.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import ACL_SAVE from './ACL_SAVE';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL SAVE', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_SAVE.transformArguments(),
+      parseArgs(ACL_SAVE),
       ['ACL', 'SAVE']
     );
   });
diff --git a/packages/client/lib/commands/ACL_SAVE.ts b/packages/client/lib/commands/ACL_SAVE.ts
index 8c2e2dab115..3989471d47b 100644
--- a/packages/client/lib/commands/ACL_SAVE.ts
+++ b/packages/client/lib/commands/ACL_SAVE.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ACL', 'SAVE'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'SAVE']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_SETUSER.spec.ts b/packages/client/lib/commands/ACL_SETUSER.spec.ts
index 10aea62ed02..9f39868e809 100644
--- a/packages/client/lib/commands/ACL_SETUSER.spec.ts
+++ b/packages/client/lib/commands/ACL_SETUSER.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import ACL_SETUSER from './ACL_SETUSER';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL SETUSER', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -8,14 +9,14 @@ describe('ACL SETUSER', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ACL_SETUSER.transformArguments('username', 'allkeys'),
+        parseArgs(ACL_SETUSER, 'username', 'allkeys'),
         ['ACL', 'SETUSER', 'username', 'allkeys']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ACL_SETUSER.transformArguments('username', ['allkeys', 'allchannels']),
+        parseArgs(ACL_SETUSER, 'username', ['allkeys', 'allchannels']),
         ['ACL', 'SETUSER', 'username', 'allkeys', 'allchannels']
       );
     });
diff --git a/packages/client/lib/commands/ACL_SETUSER.ts b/packages/client/lib/commands/ACL_SETUSER.ts
index c99fec3d9ba..3f46efa654f 100644
--- a/packages/client/lib/commands/ACL_SETUSER.ts
+++ b/packages/client/lib/commands/ACL_SETUSER.ts
@@ -1,11 +1,14 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(username: RedisArgument, rule: RedisVariadicArgument) {
-    return pushVariadicArguments(['ACL', 'SETUSER', username], rule);
+  parseCommand(parser: CommandParser, username: RedisArgument, rule: RedisVariadicArgument) {
+    parser.pushVariadic(['ACL', 'SETUSER', username]);
+    parser.pushVariadic(rule);
   },
+  transformArguments(username: RedisArgument, rule: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_USERS.spec.ts b/packages/client/lib/commands/ACL_USERS.spec.ts
index 2d433d4ec1e..d897b61e4f3 100644
--- a/packages/client/lib/commands/ACL_USERS.spec.ts
+++ b/packages/client/lib/commands/ACL_USERS.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import ACL_USERS from './ACL_USERS';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL USERS', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_USERS.transformArguments(),
+      parseArgs(ACL_USERS),
       ['ACL', 'USERS']
     );
   });
diff --git a/packages/client/lib/commands/ACL_USERS.ts b/packages/client/lib/commands/ACL_USERS.ts
index ee8c619f25f..116fbc5d764 100644
--- a/packages/client/lib/commands/ACL_USERS.ts
+++ b/packages/client/lib/commands/ACL_USERS.ts
@@ -1,10 +1,12 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ACL', 'USERS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'USERS']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ACL_WHOAMI.spec.ts b/packages/client/lib/commands/ACL_WHOAMI.spec.ts
index 24a5cbd1d63..f939c657a7a 100644
--- a/packages/client/lib/commands/ACL_WHOAMI.spec.ts
+++ b/packages/client/lib/commands/ACL_WHOAMI.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import ACL_WHOAMI from './ACL_WHOAMI';
+import { parseArgs } from './generic-transformers';
 
 describe('ACL WHOAMI', () => {
   testUtils.isVersionGreaterThanHook([6]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ACL_WHOAMI.transformArguments(),
+      parseArgs(ACL_WHOAMI),
       ['ACL', 'WHOAMI']
     );
   });
diff --git a/packages/client/lib/commands/ACL_WHOAMI.ts b/packages/client/lib/commands/ACL_WHOAMI.ts
index 81a1c84a3c6..86a0803a7d3 100644
--- a/packages/client/lib/commands/ACL_WHOAMI.ts
+++ b/packages/client/lib/commands/ACL_WHOAMI.ts
@@ -1,10 +1,12 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ACL', 'WHOAMI'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['ACL', 'WHOAMI']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/APPEND.spec.ts b/packages/client/lib/commands/APPEND.spec.ts
index ca18a00ac42..925c16917b9 100644
--- a/packages/client/lib/commands/APPEND.spec.ts
+++ b/packages/client/lib/commands/APPEND.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import APPEND from './APPEND';
+import { parseArgs } from './generic-transformers';
 
 describe('APPEND', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      APPEND.transformArguments('key', 'value'),
+      parseArgs(APPEND, 'key', 'value'),
       ['APPEND', 'key', 'value']
     );
   });
diff --git a/packages/client/lib/commands/APPEND.ts b/packages/client/lib/commands/APPEND.ts
index 1bc01024998..ebca35fe69e 100644
--- a/packages/client/lib/commands/APPEND.ts
+++ b/packages/client/lib/commands/APPEND.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, value: RedisArgument) {
-    return ['APPEND', key, value];
+  parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) {
+    parser.pushVariadic(['APPEND', key, value]);
   },
+
+  transformArguments(key: RedisArgument, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ASKING.spec.ts b/packages/client/lib/commands/ASKING.spec.ts
index bd83bec599f..7be4d25d449 100644
--- a/packages/client/lib/commands/ASKING.spec.ts
+++ b/packages/client/lib/commands/ASKING.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import ASKING from './ASKING';
+import { parseArgs } from './generic-transformers';
 
 describe('ASKING', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ASKING.transformArguments(),
+      parseArgs(ASKING),
       ['ASKING']
     );
   });
diff --git a/packages/client/lib/commands/ASKING.ts b/packages/client/lib/commands/ASKING.ts
index c6ada477ee4..b97f00b356d 100644
--- a/packages/client/lib/commands/ASKING.ts
+++ b/packages/client/lib/commands/ASKING.ts
@@ -1,10 +1,14 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
+
+export const ASKING_CMD = ['ASKING'];
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ASKING'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(ASKING_CMD);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/AUTH.spec.ts b/packages/client/lib/commands/AUTH.spec.ts
index 2da016ba873..762dd24f16a 100644
--- a/packages/client/lib/commands/AUTH.spec.ts
+++ b/packages/client/lib/commands/AUTH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import AUTH from './AUTH';
+import { parseArgs } from './generic-transformers';
 
 describe('AUTH', () => {
   describe('transformArguments', () => {
     it('password only', () => {
       assert.deepEqual(
-        AUTH.transformArguments({
+        parseArgs(AUTH, {
           password: 'password'
         }),
         ['AUTH', 'password']
@@ -14,7 +15,7 @@ describe('AUTH', () => {
 
     it('username & password', () => {
       assert.deepEqual(
-        AUTH.transformArguments({
+        parseArgs(AUTH, {
           username: 'username',
           password: 'password'
         }),
diff --git a/packages/client/lib/commands/AUTH.ts b/packages/client/lib/commands/AUTH.ts
index 4c7a0b0c765..c9c53683e87 100644
--- a/packages/client/lib/commands/AUTH.ts
+++ b/packages/client/lib/commands/AUTH.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface AuthOptions {
   username?: RedisArgument;
@@ -8,16 +9,13 @@ export interface AuthOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments({ username, password }: AuthOptions) {
-    const args: Array<RedisArgument> = ['AUTH'];
-
+  parseCommand(parser: CommandParser, { username, password }: AuthOptions) {
+    parser.push('AUTH');
     if (username !== undefined) {
-      args.push(username);
+      parser.push(username);
     }
-
-    args.push(password);
-
-    return args;
+    parser.push(password);
   },
+  transformArguments({ username, password }: AuthOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BGREWRITEAOF.spec.ts b/packages/client/lib/commands/BGREWRITEAOF.spec.ts
index 5447fc70a79..f58ec9a5762 100644
--- a/packages/client/lib/commands/BGREWRITEAOF.spec.ts
+++ b/packages/client/lib/commands/BGREWRITEAOF.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BGREWRITEAOF from './BGREWRITEAOF';
+import { parseArgs } from './generic-transformers';
 
 describe('BGREWRITEAOF', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      BGREWRITEAOF.transformArguments(),
+      parseArgs(BGREWRITEAOF),
       ['BGREWRITEAOF']
     );
   });
diff --git a/packages/client/lib/commands/BGREWRITEAOF.ts b/packages/client/lib/commands/BGREWRITEAOF.ts
index 5f9a46e318f..24e26255bb1 100644
--- a/packages/client/lib/commands/BGREWRITEAOF.ts
+++ b/packages/client/lib/commands/BGREWRITEAOF.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['BGREWRITEAOF'];
+  parseCommand(parser: CommandParser) {
+    parser.push('BGREWRITEAOF');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BGSAVE.spec.ts b/packages/client/lib/commands/BGSAVE.spec.ts
index 7944722dd56..dcf7b815119 100644
--- a/packages/client/lib/commands/BGSAVE.spec.ts
+++ b/packages/client/lib/commands/BGSAVE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BGSAVE from './BGSAVE';
+import { parseArgs } from './generic-transformers';
 
 describe('BGSAVE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        BGSAVE.transformArguments(),
+        parseArgs(BGSAVE),
         ['BGSAVE']
       );
     });
 
     it('with SCHEDULE', () => {
       assert.deepEqual(
-        BGSAVE.transformArguments({
+        parseArgs(BGSAVE, {
           SCHEDULE: true
         }),
         ['BGSAVE', 'SCHEDULE']
diff --git a/packages/client/lib/commands/BGSAVE.ts b/packages/client/lib/commands/BGSAVE.ts
index dc0f5056708..ced223cdae5 100644
--- a/packages/client/lib/commands/BGSAVE.ts
+++ b/packages/client/lib/commands/BGSAVE.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface BgSaveOptions {
   SCHEDULE?: boolean;
@@ -7,14 +8,12 @@ export interface BgSaveOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(options?: BgSaveOptions) {
-    const args = ['BGSAVE'];
-    
+  parseCommand(parser: CommandParser, options?: BgSaveOptions) {
+    parser.push('BGSAVE');
     if (options?.SCHEDULE) {
-      args.push('SCHEDULE');
+      parser.push('SCHEDULE');
     }
-
-    return args;
   },
+  transformArguments(options?: BgSaveOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BITCOUNT.spec.ts b/packages/client/lib/commands/BITCOUNT.spec.ts
index ceb6476a31c..e2990472948 100644
--- a/packages/client/lib/commands/BITCOUNT.spec.ts
+++ b/packages/client/lib/commands/BITCOUNT.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BITCOUNT from './BITCOUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('BITCOUNT', () => {
-  describe('transformArguments', () => {
+  describe('parseCommand', () => {
     it('simple', () => {
       assert.deepEqual(
-        BITCOUNT.transformArguments('key'),
+        parseArgs(BITCOUNT, 'key'),
         ['BITCOUNT', 'key']
       );
     });
@@ -14,7 +15,7 @@ describe('BITCOUNT', () => {
     describe('with range', () => {
       it('simple', () => {
         assert.deepEqual(
-          BITCOUNT.transformArguments('key', {
+          parseArgs(BITCOUNT, 'key', {
             start: 0,
             end: 1
           }),
@@ -24,7 +25,7 @@ describe('BITCOUNT', () => {
 
       it('with mode', () => {
         assert.deepEqual(
-          BITCOUNT.transformArguments('key', {
+          parseArgs(BITCOUNT, 'key', {
             start: 0,
             end: 1,
             mode: 'BIT'
diff --git a/packages/client/lib/commands/BITCOUNT.ts b/packages/client/lib/commands/BITCOUNT.ts
index 6ec6b89be8b..a9fa59bf8cd 100644
--- a/packages/client/lib/commands/BITCOUNT.ts
+++ b/packages/client/lib/commands/BITCOUNT.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface BitCountRange {
   start: number;
@@ -9,21 +10,19 @@ export interface BitCountRange {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, range?: BitCountRange) {
-    const args = ['BITCOUNT', key];
-
+  parseCommand(parser: CommandParser, key: RedisArgument, range?: BitCountRange) {
+    parser.setCachable();
+    parser.push('BITCOUNT');
+    parser.pushKey(key);
     if (range) {
-      args.push(
-        range.start.toString(),
-        range.end.toString()
-      );
+      parser.push(range.start.toString());
+      parser.push(range.end.toString());
 
       if (range.mode) {
-        args.push(range.mode);
+        parser.push(range.mode);
       }
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, range?: BitCountRange) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BITFIELD.spec.ts b/packages/client/lib/commands/BITFIELD.spec.ts
index 7f805755493..5fcc112466b 100644
--- a/packages/client/lib/commands/BITFIELD.spec.ts
+++ b/packages/client/lib/commands/BITFIELD.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BITFIELD from './BITFIELD';
+import { parseArgs } from './generic-transformers';
 
 describe('BITFIELD', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      BITFIELD.transformArguments('key', [{
+      parseArgs(BITFIELD, 'key', [{
         operation: 'OVERFLOW',
         behavior: 'WRAP'
       }, {
diff --git a/packages/client/lib/commands/BITFIELD.ts b/packages/client/lib/commands/BITFIELD.ts
index 5d7d4bf7282..0f9beb35e13 100644
--- a/packages/client/lib/commands/BITFIELD.ts
+++ b/packages/client/lib/commands/BITFIELD.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type BitFieldEncoding = `${'i' | 'u'}${number}`;
 
@@ -41,47 +42,55 @@ export type BitFieldRoOperations = Array<
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, operations: BitFieldOperations) {
-    const args = ['BITFIELD', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, operations: BitFieldOperations) {
+    parser.push('BITFIELD');
+    parser.pushKey(key);
 
     for (const options of operations) {
       switch (options.operation) {
         case 'GET':
-          args.push(
-            'GET',
-            options.encoding,
-            options.offset.toString()
+          parser.pushVariadic(
+            [
+              'GET',
+              options.encoding,
+              options.offset.toString()
+            ]
           );
           break;
 
         case 'SET':
-          args.push(
-            'SET',
-            options.encoding,
-            options.offset.toString(),
-            options.value.toString()
+          parser.pushVariadic(
+            [
+              'SET',
+              options.encoding,
+              options.offset.toString(),
+              options.value.toString()
+            ]
           );
           break;
 
         case 'INCRBY':
-          args.push(
-            'INCRBY',
-            options.encoding,
-            options.offset.toString(),
-            options.increment.toString()
+          parser.pushVariadic(
+            [
+              'INCRBY',
+              options.encoding,
+              options.offset.toString(),
+              options.increment.toString()
+            ]
           );
           break;
 
         case 'OVERFLOW':
-          args.push(
-            'OVERFLOW',
-            options.behavior
+          parser.pushVariadic(
+            [
+              'OVERFLOW',
+              options.behavior
+            ]
           );
           break;
       }
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, operations: BitFieldOperations) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BITFIELD_RO.spec.ts b/packages/client/lib/commands/BITFIELD_RO.spec.ts
index 0793100193f..f2c1797412f 100644
--- a/packages/client/lib/commands/BITFIELD_RO.spec.ts
+++ b/packages/client/lib/commands/BITFIELD_RO.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BITFIELD_RO from './BITFIELD_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('BITFIELD_RO', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
-  it('transformArguments', () => {
+  it('parseCommand', () => {
     assert.deepEqual(
-      BITFIELD_RO.transformArguments('key', [{
+      parseArgs(BITFIELD_RO, 'key', [{
         encoding: 'i8',
         offset: 0
       }]),
diff --git a/packages/client/lib/commands/BITFIELD_RO.ts b/packages/client/lib/commands/BITFIELD_RO.ts
index 99e500abc04..5b171495557 100644
--- a/packages/client/lib/commands/BITFIELD_RO.ts
+++ b/packages/client/lib/commands/BITFIELD_RO.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { BitFieldGetOperation } from './BITFIELD';
 
 export type BitFieldRoOperations = Array<
@@ -8,18 +9,17 @@ export type BitFieldRoOperations = Array<
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, operations: BitFieldRoOperations) {
-    const args = ['BITFIELD_RO', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, operations: BitFieldRoOperations) {
+    parser.setCachable();
+    parser.push('BITFIELD_RO');
+    parser.pushKey(key);
 
     for (const operation of operations) {
-      args.push(
-        'GET',
-        operation.encoding,
-        operation.offset.toString()
-      );
+      parser.push('GET');
+      parser.push(operation.encoding);
+      parser.push(operation.offset.toString())
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, operations: BitFieldRoOperations) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<NumberReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BITOP.spec.ts b/packages/client/lib/commands/BITOP.spec.ts
index 4df1782467f..25fe48fc13c 100644
--- a/packages/client/lib/commands/BITOP.spec.ts
+++ b/packages/client/lib/commands/BITOP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BITOP from './BITOP';
+import { parseArgs } from './generic-transformers';
 
 describe('BITOP', () => {
   describe('transformArguments', () => {
     it('single key', () => {
       assert.deepEqual(
-        BITOP.transformArguments('AND', 'destKey', 'key'),
+        parseArgs(BITOP, 'AND', 'destKey', 'key'),
         ['BITOP', 'AND', 'destKey', 'key']
       );
     });
 
     it('multiple keys', () => {
       assert.deepEqual(
-        BITOP.transformArguments('AND', 'destKey', ['1', '2']),
+        parseArgs(BITOP, 'AND', 'destKey', ['1', '2']),
         ['BITOP', 'AND', 'destKey', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/BITOP.ts b/packages/client/lib/commands/BITOP.ts
index 4c34845699e..d9d27150f12 100644
--- a/packages/client/lib/commands/BITOP.ts
+++ b/packages/client/lib/commands/BITOP.ts
@@ -1,17 +1,26 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     operation: BitOperations,
     destKey: RedisArgument,
     key: RedisVariadicArgument
   ) {
-    return pushVariadicArguments(['BITOP', operation, destKey], key);
+      parser.pushVariadic(['BITOP', operation]);
+      parser.pushKey(destKey);
+      parser.pushKeys(key);
   },
+  transformArguments(
+    operation: BitOperations,
+    destKey: RedisArgument,
+    key: RedisVariadicArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BITPOS.spec.ts b/packages/client/lib/commands/BITPOS.spec.ts
index 61940560057..c699deab83c 100644
--- a/packages/client/lib/commands/BITPOS.spec.ts
+++ b/packages/client/lib/commands/BITPOS.spec.ts
@@ -1,33 +1,34 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import BITPOS from './BITPOS';
+import { parseArgs } from './generic-transformers';
 
 describe('BITPOS', () => {
-  describe('transformArguments', () => {
+  describe('parseCommand', () => {
     it('simple', () => {
       assert.deepEqual(
-        BITPOS.transformArguments('key', 1),
+        parseArgs(BITPOS, 'key', 1),
         ['BITPOS', 'key', '1']
       );
     });
 
     it('with start', () => {
       assert.deepEqual(
-        BITPOS.transformArguments('key', 1, 1),
+        parseArgs(BITPOS, 'key', 1, 1),
         ['BITPOS', 'key', '1', '1']
       );
     });
 
     it('with start and end', () => {
       assert.deepEqual(
-        BITPOS.transformArguments('key', 1, 1, -1),
+        parseArgs(BITPOS, 'key', 1, 1, -1),
         ['BITPOS', 'key', '1', '1', '-1']
       );
     });
 
     it('with start, end and mode', () => {
       assert.deepEqual(
-        BITPOS.transformArguments('key', 1, 1, -1, 'BIT'),
+        parseArgs(BITPOS, 'key', 1, 1, -1, 'BIT'),
         ['BITPOS', 'key', '1', '1', '-1', 'BIT']
       );
     });
diff --git a/packages/client/lib/commands/BITPOS.ts b/packages/client/lib/commands/BITPOS.ts
index 5d6276dffc0..1c85cdbbc81 100644
--- a/packages/client/lib/commands/BITPOS.ts
+++ b/packages/client/lib/commands/BITPOS.ts
@@ -1,31 +1,40 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { BitValue } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(parser: CommandParser,
     key: RedisArgument,
     bit: BitValue,
     start?: number,
     end?: number,
     mode?: 'BYTE' | 'BIT'
   ) {
-    const args = ['BITPOS', key, bit.toString()];
+    parser.setCachable();
+    parser.push('BITPOS');
+    parser.pushKey(key);
+    parser.push(bit.toString());
 
     if (start !== undefined) {
-      args.push(start.toString());
+      parser.push(start.toString());
     }
 
     if (end !== undefined) {
-      args.push(end.toString());
+      parser.push(end.toString());
     }
 
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    bit: BitValue,
+    start?: number,
+    end?: number,
+    mode?: 'BYTE' | 'BIT'
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BLMOVE.spec.ts b/packages/client/lib/commands/BLMOVE.spec.ts
index 0eca8c61005..d4e9e024a8c 100644
--- a/packages/client/lib/commands/BLMOVE.spec.ts
+++ b/packages/client/lib/commands/BLMOVE.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BLMOVE from './BLMOVE';
+import { parseArgs } from './generic-transformers';
 
 describe('BLMOVE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      BLMOVE.transformArguments('source', 'destination', 'LEFT', 'RIGHT', 0),
+      parseArgs(BLMOVE, 'source', 'destination', 'LEFT', 'RIGHT', 0),
       ['BLMOVE', 'source', 'destination', 'LEFT', 'RIGHT', '0']
     );
   });
diff --git a/packages/client/lib/commands/BLMOVE.ts b/packages/client/lib/commands/BLMOVE.ts
index c7e4844375f..7df0127a8a3 100644
--- a/packages/client/lib/commands/BLMOVE.ts
+++ b/packages/client/lib/commands/BLMOVE.ts
@@ -1,24 +1,28 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { ListSide } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     source: RedisArgument,
     destination: RedisArgument,
     sourceSide: ListSide,
     destinationSide: ListSide,
     timeout: number
   ) {
-    return [
-      'BLMOVE',
-      source,
-      destination,
-      sourceSide,
-      destinationSide,
-      timeout.toString()
-    ];
+    parser.push('BLMOVE');
+    parser.pushKeys([source, destination]);
+    parser.pushVariadic([sourceSide, destinationSide, timeout.toString()])
   },
+  transformArguments(
+    source: RedisArgument,
+    destination: RedisArgument,
+    sourceSide: ListSide,
+    destinationSide: ListSide,
+    timeout: number
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BLMPOP.spec.ts b/packages/client/lib/commands/BLMPOP.spec.ts
index b40556b1e46..6cda524b50f 100644
--- a/packages/client/lib/commands/BLMPOP.spec.ts
+++ b/packages/client/lib/commands/BLMPOP.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BLMPOP from './BLMPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('BLMPOP', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('BLMPOP', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        BLMPOP.transformArguments(0, 'key', 'LEFT'),
+        parseArgs(BLMPOP, 0, 'key', 'LEFT'),
         ['BLMPOP', '0', '1', 'key', 'LEFT']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        BLMPOP.transformArguments(0, 'key', 'LEFT', {
+        parseArgs(BLMPOP, 0, 'key', 'LEFT', {
           COUNT: 1
         }),
         ['BLMPOP', '0', '1', 'key', 'LEFT', 'COUNT', '1']
diff --git a/packages/client/lib/commands/BLMPOP.ts b/packages/client/lib/commands/BLMPOP.ts
index 3122e908600..2c9c9d43c51 100644
--- a/packages/client/lib/commands/BLMPOP.ts
+++ b/packages/client/lib/commands/BLMPOP.ts
@@ -1,17 +1,17 @@
 import { Command } from '../RESP/types';
-import LMPOP, { LMPopArguments, transformLMPopArguments } from './LMPOP';
+import { CommandParser } from '../client/parser';
+import LMPOP, { LMPopArguments, parseLMPopArguments } from './LMPOP';
 
 export default {
   FIRST_KEY_INDEX: 3,
   IS_READ_ONLY: false,
+  parseCommand(parser: CommandParser, timeout: number, ...args: LMPopArguments) {
+    parser.pushVariadic(['BLMPOP', timeout.toString()]);
+    parseLMPopArguments(parser, ...args);
+  }, 
   transformArguments(
     timeout: number,
     ...args: LMPopArguments
-  ) {
-    return transformLMPopArguments(
-      ['BLMPOP', timeout.toString()],
-      ...args
-    );
-  },
+  ) { return [] },
   transformReply: LMPOP.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BLPOP.spec.ts b/packages/client/lib/commands/BLPOP.spec.ts
index 4bcc08d0fc9..1bb53a774b7 100644
--- a/packages/client/lib/commands/BLPOP.spec.ts
+++ b/packages/client/lib/commands/BLPOP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BLPOP from './BLPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('BLPOP', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        BLPOP.transformArguments('key', 0),
+        parseArgs(BLPOP, 'key', 0),
         ['BLPOP', 'key', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        BLPOP.transformArguments(['1', '2'], 0),
+        parseArgs(BLPOP, ['1', '2'], 0),
         ['BLPOP', '1', '2', '0']
       );
     });
diff --git a/packages/client/lib/commands/BLPOP.ts b/packages/client/lib/commands/BLPOP.ts
index c9f8b4775eb..649ff29f8db 100644
--- a/packages/client/lib/commands/BLPOP.ts
+++ b/packages/client/lib/commands/BLPOP.ts
@@ -1,17 +1,19 @@
 import { UnwrapReply, NullReply, TuplesReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser, key: RedisVariadicArgument, timeout: number) {
+    parser.push('BLPOP');
+    parser.pushKeys(key);
+    parser.push(timeout.toString());
+  },
   transformArguments(
     key: RedisVariadicArgument,
     timeout: number
-  ) {
-    const args = pushVariadicArguments(['BLPOP'], key);
-    args.push(timeout.toString());
-    return args;
-  },
+  ) { return [] },
   transformReply(reply: UnwrapReply<NullReply | TuplesReply<[BlobStringReply, BlobStringReply]>>) {
     if (reply === null) return null;
 
diff --git a/packages/client/lib/commands/BRPOP.spec.ts b/packages/client/lib/commands/BRPOP.spec.ts
index 21631d763f4..de23bb34a92 100644
--- a/packages/client/lib/commands/BRPOP.spec.ts
+++ b/packages/client/lib/commands/BRPOP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BRPOP from './BRPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('BRPOP', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        BRPOP.transformArguments('key', 0),
+        parseArgs(BRPOP, 'key', 0),
         ['BRPOP', 'key', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        BRPOP.transformArguments(['1', '2'], 0),
+        parseArgs(BRPOP, ['1', '2'], 0),
         ['BRPOP', '1', '2', '0']
       );
     });
diff --git a/packages/client/lib/commands/BRPOP.ts b/packages/client/lib/commands/BRPOP.ts
index f9c8aaa5037..e38f701b81b 100644
--- a/packages/client/lib/commands/BRPOP.ts
+++ b/packages/client/lib/commands/BRPOP.ts
@@ -1,17 +1,19 @@
 import { Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { RedisVariadicArgument } from './generic-transformers';
 import BLPOP from './BLPOP';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser, key: RedisVariadicArgument, timeout: number) {
+    parser.push('BRPOP');
+    parser.pushKeys(key);
+    parser.push(timeout.toString());
+  },
   transformArguments(
     key: RedisVariadicArgument,
     timeout: number
-  ) {
-    const args = pushVariadicArguments(['BRPOP'], key);
-    args.push(timeout.toString());
-    return args;
-  },
+  ) { return [] },
   transformReply: BLPOP.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BRPOPLPUSH.spec.ts b/packages/client/lib/commands/BRPOPLPUSH.spec.ts
index 1f6dc48bfea..6c2a2a2c900 100644
--- a/packages/client/lib/commands/BRPOPLPUSH.spec.ts
+++ b/packages/client/lib/commands/BRPOPLPUSH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BRPOPLPUSH from './BRPOPLPUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('BRPOPLPUSH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      BRPOPLPUSH.transformArguments('source', 'destination', 0),
+      parseArgs(BRPOPLPUSH, 'source', 'destination', 0),
       ['BRPOPLPUSH', 'source', 'destination', '0']
     );
   });
diff --git a/packages/client/lib/commands/BRPOPLPUSH.ts b/packages/client/lib/commands/BRPOPLPUSH.ts
index d342ea75725..a5b982052eb 100644
--- a/packages/client/lib/commands/BRPOPLPUSH.ts
+++ b/packages/client/lib/commands/BRPOPLPUSH.ts
@@ -1,14 +1,18 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
+  parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument, timeout: number) {
+    parser.push('BRPOPLPUSH');
+    parser.pushKeys([source, destination]);
+    parser.push(timeout.toString());
+  },
   transformArguments(
     source: RedisArgument,
     destination: RedisArgument,
     timeout: number
-  ) {
-    return ['BRPOPLPUSH', source, destination, timeout.toString()];
-  },
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BZMPOP.spec.ts b/packages/client/lib/commands/BZMPOP.spec.ts
index 554e6898d62..8b082a214ee 100644
--- a/packages/client/lib/commands/BZMPOP.spec.ts
+++ b/packages/client/lib/commands/BZMPOP.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BZMPOP from './BZMPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('BZMPOP', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('BZMPOP', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        BZMPOP.transformArguments(0, 'key', 'MIN'),
+        parseArgs(BZMPOP, 0, 'key', 'MIN'),
         ['BZMPOP', '0', '1', 'key', 'MIN']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        BZMPOP.transformArguments(0, 'key', 'MIN', {
+        parseArgs(BZMPOP, 0, 'key', 'MIN', {
           COUNT: 2
         }),
         ['BZMPOP', '0', '1', 'key', 'MIN', 'COUNT', '2']
diff --git a/packages/client/lib/commands/BZMPOP.ts b/packages/client/lib/commands/BZMPOP.ts
index 030aa20c66b..0f6a9b20cc6 100644
--- a/packages/client/lib/commands/BZMPOP.ts
+++ b/packages/client/lib/commands/BZMPOP.ts
@@ -1,11 +1,18 @@
 import { Command } from '../RESP/types';
-import ZMPOP, { ZMPopArguments, transformZMPopArguments } from './ZMPOP';
+import { CommandParser } from '../client/parser';
+import ZMPOP, { ZMPopArguments } from './ZMPOP';
 
 export default {
   FIRST_KEY_INDEX: 3,
   IS_READ_ONLY: false,
-  transformArguments(timeout: number, ...args: ZMPopArguments) {
-    return transformZMPopArguments(['BZMPOP', timeout.toString()], ...args);
+  parseCommand(parser: CommandParser, timeout: number, ...args: ZMPopArguments) {
+    parser.pushVariadic(['BZMPOP', timeout.toString()]);
+    parser.pushKeysLength(args[0]);
+    parser.push(args[1]);
+    if (args[2]?.COUNT) {
+      parser.pushVariadic(['COUNT', args[2].COUNT.toString()]);
+    }
   },
+  transformArguments(timeout: number, ...args: ZMPopArguments) { return [] },
   transformReply: ZMPOP.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/BZPOPMAX.spec.ts b/packages/client/lib/commands/BZPOPMAX.spec.ts
index 1f0a4d44f07..fbf60862327 100644
--- a/packages/client/lib/commands/BZPOPMAX.spec.ts
+++ b/packages/client/lib/commands/BZPOPMAX.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BZPOPMAX from './BZPOPMAX';
+import { parseArgs } from './generic-transformers';
 
 describe('BZPOPMAX', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        BZPOPMAX.transformArguments('key', 0),
+        parseArgs(BZPOPMAX, 'key', 0),
         ['BZPOPMAX', 'key', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        BZPOPMAX.transformArguments(['1', '2'], 0),
+        parseArgs(BZPOPMAX, ['1', '2'], 0),
         ['BZPOPMAX', '1', '2', '0']
       );
     });
diff --git a/packages/client/lib/commands/BZPOPMAX.ts b/packages/client/lib/commands/BZPOPMAX.ts
index c498a3b8045..df4a9f80f91 100644
--- a/packages/client/lib/commands/BZPOPMAX.ts
+++ b/packages/client/lib/commands/BZPOPMAX.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NullReply, TuplesReply, BlobStringReply, DoubleReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
 
 export function transformBZPopArguments(
@@ -16,9 +17,12 @@ export type BZPopArguments = typeof transformBZPopArguments extends (_: any, ...
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(...args: BZPopArguments) {
-    return transformBZPopArguments('BZPOPMAX', ...args);
+  parseCommand(parser: CommandParser, ...args: BZPopArguments) {
+    parser.push('BZPOPMAX');
+    parser.pushKeys(args[0]);
+    parser.push(args[1].toString());
   },
+  transformArguments(...args: BZPopArguments) { return [] },
   transformReply: {
     2(reply: UnwrapReply<NullReply | TuplesReply<[BlobStringReply, BlobStringReply, BlobStringReply]>>) {
       return reply === null ? null : {
diff --git a/packages/client/lib/commands/BZPOPMIN.spec.ts b/packages/client/lib/commands/BZPOPMIN.spec.ts
index 7f39f7d1896..2f8cab8dedf 100644
--- a/packages/client/lib/commands/BZPOPMIN.spec.ts
+++ b/packages/client/lib/commands/BZPOPMIN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
 import BZPOPMIN from './BZPOPMIN';
+import { parseArgs } from './generic-transformers';
 
 describe('BZPOPMIN', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        BZPOPMIN.transformArguments('key', 0),
+        parseArgs(BZPOPMIN, 'key', 0),
         ['BZPOPMIN', 'key', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        BZPOPMIN.transformArguments(['1', '2'], 0),
+        parseArgs(BZPOPMIN, ['1', '2'], 0),
         ['BZPOPMIN', '1', '2', '0']
       );
     });
diff --git a/packages/client/lib/commands/BZPOPMIN.ts b/packages/client/lib/commands/BZPOPMIN.ts
index f27e623528e..80c2df8a17f 100644
--- a/packages/client/lib/commands/BZPOPMIN.ts
+++ b/packages/client/lib/commands/BZPOPMIN.ts
@@ -1,12 +1,16 @@
 import { Command } from '../RESP/types';
-import BZPOPMAX, { BZPopArguments, transformBZPopArguments } from './BZPOPMAX';
+import { CommandParser } from '../client/parser';
+import BZPOPMAX, { BZPopArguments } from './BZPOPMAX';
 
 export default {
   FIRST_KEY_INDEX: BZPOPMAX.FIRST_KEY_INDEX,
   IS_READ_ONLY: BZPOPMAX.IS_READ_ONLY,
-  transformArguments(...args: BZPopArguments) {
-    return transformBZPopArguments('BZPOPMIN', ...args);
+  parseCommand(parser: CommandParser, ...args: BZPopArguments) {
+    parser.push('BZPOPMIN');
+    parser.pushKeys(args[0]);
+    parser.push(args[1].toString());
   },
+  transformArguments(...args: BZPopArguments) { return [] },
   transformReply: BZPOPMAX.transformReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/CLIENT_CACHING.spec.ts b/packages/client/lib/commands/CLIENT_CACHING.spec.ts
index 34023f98922..ad3511b3e97 100644
--- a/packages/client/lib/commands/CLIENT_CACHING.spec.ts
+++ b/packages/client/lib/commands/CLIENT_CACHING.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLIENT_CACHING from './CLIENT_CACHING';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT CACHING', () => {
   describe('transformArguments', () => {
     it('true', () => {
       assert.deepEqual(
-        CLIENT_CACHING.transformArguments(true),
+        parseArgs(CLIENT_CACHING, true),
         ['CLIENT', 'CACHING', 'YES']
       );
     });
 
     it('false', () => {
       assert.deepEqual(
-        CLIENT_CACHING.transformArguments(false),
+        parseArgs(CLIENT_CACHING, false),
         ['CLIENT', 'CACHING', 'NO']
       );
     });
diff --git a/packages/client/lib/commands/CLIENT_CACHING.ts b/packages/client/lib/commands/CLIENT_CACHING.ts
index 505ae152f85..82bb0c88dad 100644
--- a/packages/client/lib/commands/CLIENT_CACHING.ts
+++ b/packages/client/lib/commands/CLIENT_CACHING.ts
@@ -1,14 +1,18 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(value: boolean) {
-    return [
-      'CLIENT',
-      'CACHING',
-      value ? 'YES' : 'NO'
-    ];
+  parseCommand(parser: CommandParser, value: boolean) {
+    parser.pushVariadic(
+      [
+        'CLIENT',
+        'CACHING',
+        value ? 'YES' : 'NO'
+      ]
+    );
   },
+  transformArguments(value: boolean) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_GETNAME.spec.ts b/packages/client/lib/commands/CLIENT_GETNAME.spec.ts
index 8975f1fee9c..5b0dfdb8437 100644
--- a/packages/client/lib/commands/CLIENT_GETNAME.spec.ts
+++ b/packages/client/lib/commands/CLIENT_GETNAME.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_GETNAME from './CLIENT_GETNAME';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT GETNAME', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_GETNAME.transformArguments(),
+      parseArgs(CLIENT_GETNAME),
       ['CLIENT', 'GETNAME']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_GETNAME.ts b/packages/client/lib/commands/CLIENT_GETNAME.ts
index c46b576407b..4b08f2767e8 100644
--- a/packages/client/lib/commands/CLIENT_GETNAME.ts
+++ b/packages/client/lib/commands/CLIENT_GETNAME.ts
@@ -1,13 +1,12 @@
 import { BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return [
-      'CLIENT',
-      'GETNAME'
-    ];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'GETNAME']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_GETREDIR.spec.ts b/packages/client/lib/commands/CLIENT_GETREDIR.spec.ts
index 5cfedf2a4e7..a7c375fec26 100644
--- a/packages/client/lib/commands/CLIENT_GETREDIR.spec.ts
+++ b/packages/client/lib/commands/CLIENT_GETREDIR.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLIENT_GETREDIR from './CLIENT_GETREDIR';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT GETREDIR', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_GETREDIR.transformArguments(),
+      parseArgs(CLIENT_GETREDIR),
       ['CLIENT', 'GETREDIR']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_GETREDIR.ts b/packages/client/lib/commands/CLIENT_GETREDIR.ts
index ae0b601b4e8..5a5a0998794 100644
--- a/packages/client/lib/commands/CLIENT_GETREDIR.ts
+++ b/packages/client/lib/commands/CLIENT_GETREDIR.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLIENT', 'GETREDIR']
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'GETREDIR']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_ID.spec.ts b/packages/client/lib/commands/CLIENT_ID.spec.ts
index 7b51e6bd930..51b308adf2c 100644
--- a/packages/client/lib/commands/CLIENT_ID.spec.ts
+++ b/packages/client/lib/commands/CLIENT_ID.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_ID from './CLIENT_ID';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT ID', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_ID.transformArguments(),
+      parseArgs(CLIENT_ID),
       ['CLIENT', 'ID']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_ID.ts b/packages/client/lib/commands/CLIENT_ID.ts
index 165ab1931eb..317f2be7497 100644
--- a/packages/client/lib/commands/CLIENT_ID.ts
+++ b/packages/client/lib/commands/CLIENT_ID.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLIENT', 'ID'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'ID']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_INFO.spec.ts b/packages/client/lib/commands/CLIENT_INFO.spec.ts
index 0aba384aa3a..50345a46ce3 100644
--- a/packages/client/lib/commands/CLIENT_INFO.spec.ts
+++ b/packages/client/lib/commands/CLIENT_INFO.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import CLIENT_INFO from './CLIENT_INFO';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT INFO', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_INFO.transformArguments(),
+      parseArgs(CLIENT_INFO),
       ['CLIENT', 'INFO']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts
index 88721e2f8b9..bc59d238dc4 100644
--- a/packages/client/lib/commands/CLIENT_INFO.ts
+++ b/packages/client/lib/commands/CLIENT_INFO.ts
@@ -1,4 +1,5 @@
 import { Command, VerbatimStringReply } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface ClientInfoReply {
   id: number;
@@ -58,9 +59,10 @@ const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g;
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLIENT', 'INFO']
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'INFO']);
   },
+  transformArguments() { return [] },
   transformReply(rawReply: VerbatimStringReply) {
     const map: Record<string, string> = {};
     for (const item of rawReply.toString().matchAll(CLIENT_INFO_REGEX)) {
diff --git a/packages/client/lib/commands/CLIENT_KILL.spec.ts b/packages/client/lib/commands/CLIENT_KILL.spec.ts
index 0685c46ba4a..f9fdfc62524 100644
--- a/packages/client/lib/commands/CLIENT_KILL.spec.ts
+++ b/packages/client/lib/commands/CLIENT_KILL.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import CLIENT_KILL, { CLIENT_KILL_FILTERS } from './CLIENT_KILL';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT KILL', () => {
   describe('transformArguments', () => {
     it('ADDRESS', () => {
       assert.deepEqual(
-        CLIENT_KILL.transformArguments({
+        parseArgs(CLIENT_KILL, {
           filter: CLIENT_KILL_FILTERS.ADDRESS,
           address: 'ip:6379'
         }),
@@ -15,7 +16,7 @@ describe('CLIENT KILL', () => {
 
     it('LOCAL_ADDRESS', () => {
       assert.deepEqual(
-        CLIENT_KILL.transformArguments({
+        parseArgs(CLIENT_KILL, {
           filter: CLIENT_KILL_FILTERS.LOCAL_ADDRESS,
           localAddress: 'ip:6379'
         }),
@@ -26,7 +27,7 @@ describe('CLIENT KILL', () => {
     describe('ID', () => {
       it('string', () => {
         assert.deepEqual(
-          CLIENT_KILL.transformArguments({
+          parseArgs(CLIENT_KILL, {
             filter: CLIENT_KILL_FILTERS.ID,
             id: '1'
           }),
@@ -36,7 +37,7 @@ describe('CLIENT KILL', () => {
 
       it('number', () => {
         assert.deepEqual(
-          CLIENT_KILL.transformArguments({
+          parseArgs(CLIENT_KILL, {
             filter: CLIENT_KILL_FILTERS.ID,
             id: 1
           }),
@@ -47,7 +48,7 @@ describe('CLIENT KILL', () => {
 
     it('TYPE', () => {
       assert.deepEqual(
-        CLIENT_KILL.transformArguments({
+        parseArgs(CLIENT_KILL, {
           filter: CLIENT_KILL_FILTERS.TYPE,
           type: 'master'
         }),
@@ -57,7 +58,7 @@ describe('CLIENT KILL', () => {
 
     it('USER', () => {
       assert.deepEqual(
-        CLIENT_KILL.transformArguments({
+        parseArgs(CLIENT_KILL, {
           filter: CLIENT_KILL_FILTERS.USER,
           username: 'username'
         }),
@@ -68,14 +69,14 @@ describe('CLIENT KILL', () => {
     describe('SKIP_ME', () => {
       it('undefined', () => {
         assert.deepEqual(
-          CLIENT_KILL.transformArguments(CLIENT_KILL_FILTERS.SKIP_ME),
+          parseArgs(CLIENT_KILL, CLIENT_KILL_FILTERS.SKIP_ME),
           ['CLIENT', 'KILL', 'SKIPME']
         );
       });
 
       it('true', () => {
         assert.deepEqual(
-          CLIENT_KILL.transformArguments({
+          parseArgs(CLIENT_KILL, {
             filter: CLIENT_KILL_FILTERS.SKIP_ME,
             skipMe: true
           }),
@@ -85,7 +86,7 @@ describe('CLIENT KILL', () => {
 
       it('false', () => {
         assert.deepEqual(
-          CLIENT_KILL.transformArguments({
+          parseArgs(CLIENT_KILL, {
             filter: CLIENT_KILL_FILTERS.SKIP_ME,
             skipMe: false
           }),
@@ -96,7 +97,7 @@ describe('CLIENT KILL', () => {
 
     it('TYPE & SKIP_ME', () => {
       assert.deepEqual(
-        CLIENT_KILL.transformArguments([
+        parseArgs(CLIENT_KILL, [
           {
             filter: CLIENT_KILL_FILTERS.TYPE,
             type: 'master'
diff --git a/packages/client/lib/commands/CLIENT_KILL.ts b/packages/client/lib/commands/CLIENT_KILL.ts
index 81d0bc85ee7..643c4568a30 100644
--- a/packages/client/lib/commands/CLIENT_KILL.ts
+++ b/packages/client/lib/commands/CLIENT_KILL.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const CLIENT_KILL_FILTERS = {
   ADDRESS: 'ADDR',
@@ -44,41 +45,41 @@ export type ClientKillFilter = ClientKillAddress | ClientKillLocalAddress | Clie
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(filters: ClientKillFilter | Array<ClientKillFilter>) {
-    const args = ['CLIENT', 'KILL'];
+  parseCommand(parser: CommandParser, filters: ClientKillFilter | Array<ClientKillFilter>) {
+    parser.pushVariadic(['CLIENT', 'KILL']);
 
     if (Array.isArray(filters)) {
       for (const filter of filters) {
-        pushFilter(args, filter);
+        pushFilter(parser, filter);
       }
     } else {
-      pushFilter(args, filters);
+      pushFilter(parser, filters);
     }
 
-    return args;
   },
+  transformArguments(filters: ClientKillFilter | Array<ClientKillFilter>) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
 
-function pushFilter(args: Array<RedisArgument>, filter: ClientKillFilter): void {
+function pushFilter(parser: CommandParser, filter: ClientKillFilter): void {
   if (filter === CLIENT_KILL_FILTERS.SKIP_ME) {
-    args.push('SKIPME');
+    parser.push('SKIPME');
     return;
   }
 
-  args.push(filter.filter);
+  parser.push(filter.filter);
 
   switch (filter.filter) {
     case CLIENT_KILL_FILTERS.ADDRESS:
-      args.push(filter.address);
+      parser.push(filter.address);
       break;
 
     case CLIENT_KILL_FILTERS.LOCAL_ADDRESS:
-      args.push(filter.localAddress);
+      parser.push(filter.localAddress);
       break;
 
     case CLIENT_KILL_FILTERS.ID:
-      args.push(
+      parser.push(
         typeof filter.id === 'number' ?
           filter.id.toString() :
           filter.id
@@ -86,15 +87,15 @@ function pushFilter(args: Array<RedisArgument>, filter: ClientKillFilter): void
       break;
 
     case CLIENT_KILL_FILTERS.TYPE:
-      args.push(filter.type);
+      parser.push(filter.type);
       break;
 
     case CLIENT_KILL_FILTERS.USER:
-      args.push(filter.username);
+      parser.push(filter.username);
       break;
 
     case CLIENT_KILL_FILTERS.SKIP_ME:
-      args.push(filter.skipMe ? 'yes' : 'no');
+      parser.push(filter.skipMe ? 'yes' : 'no');
       break;
   }
 }
diff --git a/packages/client/lib/commands/CLIENT_LIST.spec.ts b/packages/client/lib/commands/CLIENT_LIST.spec.ts
index e967a8dc0ff..34709c5f14f 100644
--- a/packages/client/lib/commands/CLIENT_LIST.spec.ts
+++ b/packages/client/lib/commands/CLIENT_LIST.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import CLIENT_LIST from './CLIENT_LIST';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT LIST', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLIENT_LIST.transformArguments(),
+        parseArgs(CLIENT_LIST),
         ['CLIENT', 'LIST']
       );
     });
 
     it('with TYPE', () => {
       assert.deepEqual(
-        CLIENT_LIST.transformArguments({
+        parseArgs(CLIENT_LIST, {
           TYPE: 'NORMAL'
         }),
         ['CLIENT', 'LIST', 'TYPE', 'NORMAL']
@@ -22,7 +23,7 @@ describe('CLIENT LIST', () => {
 
     it('with ID', () => {
       assert.deepEqual(
-        CLIENT_LIST.transformArguments({
+        parseArgs(CLIENT_LIST, {
           ID: ['1', '2']
         }),
         ['CLIENT', 'LIST', 'ID', '1', '2']
diff --git a/packages/client/lib/commands/CLIENT_LIST.ts b/packages/client/lib/commands/CLIENT_LIST.ts
index dc43fb8855d..ad6c8f55ffc 100644
--- a/packages/client/lib/commands/CLIENT_LIST.ts
+++ b/packages/client/lib/commands/CLIENT_LIST.ts
@@ -1,6 +1,6 @@
 import { RedisArgument, VerbatimStringReply, Command } from '../RESP/types';
-import { pushVariadicArguments } from './generic-transformers';
 import CLIENT_INFO, { ClientInfoReply } from './CLIENT_INFO';
+import { CommandParser } from '../client/parser';
 
 export interface ListFilterType {
   TYPE: 'NORMAL' | 'MASTER' | 'REPLICA' | 'PUBSUB';
@@ -17,20 +17,18 @@ export type ListFilter = ListFilterType | ListFilterId;
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(filter?: ListFilter) {
-    let args: Array<RedisArgument> = ['CLIENT', 'LIST'];
-
+  parseCommand(parser: CommandParser, filter?: ListFilter) {
+    parser.pushVariadic(['CLIENT', 'LIST']);
     if (filter) {
       if (filter.TYPE !== undefined) {
-        args.push('TYPE', filter.TYPE);
+        parser.pushVariadic(['TYPE', filter.TYPE]);
       } else {
-        args.push('ID');
-        args = pushVariadicArguments(args, filter.ID);
+        parser.push('ID');
+        parser.pushVariadic(filter.ID);
       }
     }
-
-    return args;
   },
+  transformArguments(filter?: ListFilter) { return [] },
   transformReply(rawReply: VerbatimStringReply): Array<ClientInfoReply> {
     const split = rawReply.toString().split('\n'),
       length = split.length - 1,
diff --git a/packages/client/lib/commands/CLIENT_NO-EVICT.spec.ts b/packages/client/lib/commands/CLIENT_NO-EVICT.spec.ts
index 5de4dfd7604..50afd413492 100644
--- a/packages/client/lib/commands/CLIENT_NO-EVICT.spec.ts
+++ b/packages/client/lib/commands/CLIENT_NO-EVICT.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_NO_EVICT from './CLIENT_NO-EVICT';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT NO-EVICT', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('CLIENT NO-EVICT', () => {
   describe('transformArguments', () => {
     it('true', () => {
       assert.deepEqual(
-        CLIENT_NO_EVICT.transformArguments(true),
+        parseArgs(CLIENT_NO_EVICT, true),
         ['CLIENT', 'NO-EVICT', 'ON']
       );
     });
 
     it('false', () => {
       assert.deepEqual(
-        CLIENT_NO_EVICT.transformArguments(false),
+        parseArgs(CLIENT_NO_EVICT, false),
         ['CLIENT', 'NO-EVICT', 'OFF']
       );
     });
diff --git a/packages/client/lib/commands/CLIENT_NO-EVICT.ts b/packages/client/lib/commands/CLIENT_NO-EVICT.ts
index 82aa50074ba..407e4036896 100644
--- a/packages/client/lib/commands/CLIENT_NO-EVICT.ts
+++ b/packages/client/lib/commands/CLIENT_NO-EVICT.ts
@@ -1,14 +1,18 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(value: boolean) {
-    return [
-      'CLIENT',
-      'NO-EVICT',
-      value ? 'ON' : 'OFF'
-    ];
+  parseCommand(parser: CommandParser, value: boolean) {
+    parser.pushVariadic(
+      [
+        'CLIENT',
+        'NO-EVICT',
+        value ? 'ON' : 'OFF'
+      ]
+    );
   },
+  transformArguments(value: boolean) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts b/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
index e58c22d9c6e..ec5c9f18ae9 100644
--- a/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
+++ b/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_NO_TOUCH from './CLIENT_NO-TOUCH';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT NO-TOUCH', () => {
   testUtils.isVersionGreaterThanHook([7, 2]);
@@ -8,14 +9,14 @@ describe('CLIENT NO-TOUCH', () => {
   describe('transformArguments', () => {
     it('true', () => {
       assert.deepEqual(
-        CLIENT_NO_TOUCH.transformArguments(true),
+        parseArgs(CLIENT_NO_TOUCH, true),
         ['CLIENT', 'NO-TOUCH', 'ON']
       );
     });
 
     it('false', () => {
       assert.deepEqual(
-        CLIENT_NO_TOUCH.transformArguments(false),
+        parseArgs(CLIENT_NO_TOUCH, false),
         ['CLIENT', 'NO-TOUCH', 'OFF']
       );
     });
diff --git a/packages/client/lib/commands/CLIENT_NO-TOUCH.ts b/packages/client/lib/commands/CLIENT_NO-TOUCH.ts
index a6fc5eb1765..eb540dfb4cd 100644
--- a/packages/client/lib/commands/CLIENT_NO-TOUCH.ts
+++ b/packages/client/lib/commands/CLIENT_NO-TOUCH.ts
@@ -1,15 +1,19 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(value: boolean) {
-    return [
-      'CLIENT',
-      'NO-TOUCH',
-      value ? 'ON' : 'OFF'
-    ];
+  parseCommand(parser: CommandParser, value: boolean) {
+    parser.pushVariadic(
+      [
+        'CLIENT',
+        'NO-TOUCH',
+        value ? 'ON' : 'OFF'
+      ]
+    );
   },
+  transformArguments(value: boolean) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/CLIENT_PAUSE.spec.ts b/packages/client/lib/commands/CLIENT_PAUSE.spec.ts
index a30f9075072..e213433afbe 100644
--- a/packages/client/lib/commands/CLIENT_PAUSE.spec.ts
+++ b/packages/client/lib/commands/CLIENT_PAUSE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_PAUSE from './CLIENT_PAUSE';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT PAUSE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLIENT_PAUSE.transformArguments(0),
+        parseArgs(CLIENT_PAUSE, 0),
         ['CLIENT', 'PAUSE', '0']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        CLIENT_PAUSE.transformArguments(0, 'ALL'),
+        parseArgs(CLIENT_PAUSE, 0, 'ALL'),
         ['CLIENT', 'PAUSE', '0', 'ALL']
       );
     });
diff --git a/packages/client/lib/commands/CLIENT_PAUSE.ts b/packages/client/lib/commands/CLIENT_PAUSE.ts
index 87b4177ed8c..4e929c882ff 100644
--- a/packages/client/lib/commands/CLIENT_PAUSE.ts
+++ b/packages/client/lib/commands/CLIENT_PAUSE.ts
@@ -1,20 +1,15 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(timeout: number, mode?: 'WRITE' | 'ALL') {
-    const args = [
-      'CLIENT',
-      'PAUSE',
-      timeout.toString()
-    ];
-
+  parseCommand(parser: CommandParser, timeout: number, mode?: 'WRITE' | 'ALL') {
+    parser.pushVariadic(['CLIENT', 'PAUSE', timeout.toString()]);
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(timeout: number, mode?: 'WRITE' | 'ALL') { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_SETNAME.spec.ts b/packages/client/lib/commands/CLIENT_SETNAME.spec.ts
index 8e6b914791d..b2b339c3d19 100644
--- a/packages/client/lib/commands/CLIENT_SETNAME.spec.ts
+++ b/packages/client/lib/commands/CLIENT_SETNAME.spec.ts
@@ -2,11 +2,12 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 
 import CLIENT_SETNAME from './CLIENT_SETNAME';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT SETNAME', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_SETNAME.transformArguments('name'),
+      parseArgs(CLIENT_SETNAME, 'name'),
       ['CLIENT', 'SETNAME', 'name']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_SETNAME.ts b/packages/client/lib/commands/CLIENT_SETNAME.ts
index e2e2a921958..a21dbd4822e 100644
--- a/packages/client/lib/commands/CLIENT_SETNAME.ts
+++ b/packages/client/lib/commands/CLIENT_SETNAME.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(name: RedisArgument) {
-    return ['CLIENT', 'SETNAME', name];
+  parseCommand(parser: CommandParser, name: RedisArgument) {
+    parser.pushVariadic(['CLIENT', 'SETNAME', name]);
   },
+  transformArguments(name: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLIENT_TRACKING.spec.ts b/packages/client/lib/commands/CLIENT_TRACKING.spec.ts
index 98fe091fb1b..032725635ee 100644
--- a/packages/client/lib/commands/CLIENT_TRACKING.spec.ts
+++ b/packages/client/lib/commands/CLIENT_TRACKING.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_TRACKING from './CLIENT_TRACKING';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT TRACKING', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -9,14 +10,14 @@ describe('CLIENT TRACKING', () => {
     describe('true', () => {
       it('simple', () => {
         assert.deepEqual(
-          CLIENT_TRACKING.transformArguments(true),
+          parseArgs(CLIENT_TRACKING, true),
           ['CLIENT', 'TRACKING', 'ON']
         );
       });
 
       it('with REDIRECT', () => {
         assert.deepEqual(
-          CLIENT_TRACKING.transformArguments(true, {
+          parseArgs(CLIENT_TRACKING, true, {
             REDIRECT: 1
           }),
           ['CLIENT', 'TRACKING', 'ON', 'REDIRECT', '1']
@@ -26,7 +27,7 @@ describe('CLIENT TRACKING', () => {
       describe('with BCAST', () => {
         it('simple', () => {
           assert.deepEqual(
-            CLIENT_TRACKING.transformArguments(true, {
+            parseArgs(CLIENT_TRACKING, true, {
               BCAST: true
             }),
             ['CLIENT', 'TRACKING', 'ON', 'BCAST']
@@ -36,7 +37,7 @@ describe('CLIENT TRACKING', () => {
         describe('with PREFIX', () => {
           it('string', () => {
             assert.deepEqual(
-              CLIENT_TRACKING.transformArguments(true, {
+              parseArgs(CLIENT_TRACKING, true, {
                 BCAST: true,
                 PREFIX: 'prefix'
               }),
@@ -46,7 +47,7 @@ describe('CLIENT TRACKING', () => {
 
           it('array', () => {
             assert.deepEqual(
-              CLIENT_TRACKING.transformArguments(true, {
+              parseArgs(CLIENT_TRACKING, true, {
                 BCAST: true,
                 PREFIX: ['1', '2']
               }),
@@ -58,7 +59,7 @@ describe('CLIENT TRACKING', () => {
 
       it('with OPTIN', () => {
         assert.deepEqual(
-          CLIENT_TRACKING.transformArguments(true, {
+          parseArgs(CLIENT_TRACKING, true, {
             OPTIN: true
           }),
           ['CLIENT', 'TRACKING', 'ON', 'OPTIN']
@@ -67,7 +68,7 @@ describe('CLIENT TRACKING', () => {
 
       it('with OPTOUT', () => {
         assert.deepEqual(
-          CLIENT_TRACKING.transformArguments(true, {
+          parseArgs(CLIENT_TRACKING, true, {
             OPTOUT: true
           }),
           ['CLIENT', 'TRACKING', 'ON', 'OPTOUT']
@@ -76,7 +77,7 @@ describe('CLIENT TRACKING', () => {
 
       it('with NOLOOP', () => {
         assert.deepEqual(
-          CLIENT_TRACKING.transformArguments(true, {
+          parseArgs(CLIENT_TRACKING, true, {
             NOLOOP: true
           }),
           ['CLIENT', 'TRACKING', 'ON', 'NOLOOP']
@@ -86,7 +87,7 @@ describe('CLIENT TRACKING', () => {
 
     it('false', () => {
       assert.deepEqual(
-        CLIENT_TRACKING.transformArguments(false),
+        parseArgs(CLIENT_TRACKING, false),
         ['CLIENT', 'TRACKING', 'OFF']
       );
     });
diff --git a/packages/client/lib/commands/CLIENT_TRACKING.ts b/packages/client/lib/commands/CLIENT_TRACKING.ts
index a783ce35894..7c0a052fa1e 100644
--- a/packages/client/lib/commands/CLIENT_TRACKING.ts
+++ b/packages/client/lib/commands/CLIENT_TRACKING.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { RedisVariadicArgument } from './generic-transformers';
 
 interface CommonOptions {
@@ -28,49 +29,56 @@ export type ClientTrackingOptions = CommonOptions & (
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments<M extends boolean>(
+  parseCommand<M extends boolean>(
+    parser: CommandParser,
     mode: M,
     options?: M extends true ? ClientTrackingOptions : never
   ) {
-    const args: Array<RedisArgument> = [
-      'CLIENT',
-      'TRACKING',
-      mode ? 'ON' : 'OFF'
-    ];
+    parser.pushVariadic(
+      [
+        'CLIENT',
+        'TRACKING',
+        mode ? 'ON' : 'OFF'
+      ]
+    );
 
     if (mode) {
       if (options?.REDIRECT) {
-        args.push(
-          'REDIRECT',
-          options.REDIRECT.toString()
+        parser.pushVariadic(
+          [
+            'REDIRECT',
+            options.REDIRECT.toString()
+          ]
         );
       }
 
       if (isBroadcast(options)) {
-        args.push('BCAST');
+        parser.push('BCAST');
 
         if (options?.PREFIX) {
           if (Array.isArray(options.PREFIX)) {
             for (const prefix of options.PREFIX) {
-              args.push('PREFIX', prefix);
+              parser.pushVariadic(['PREFIX', prefix]);
             }
           } else {
-            args.push('PREFIX', options.PREFIX);
+            parser.pushVariadic(['PREFIX', options.PREFIX]);
           }
         }
       } else if (isOptIn(options)) {
-        args.push('OPTIN');
+        parser.push('OPTIN');
       } else if (isOptOut(options)) {
-        args.push('OPTOUT');
+        parser.push('OPTOUT');
       }
 
       if (options?.NOLOOP) {
-        args.push('NOLOOP');
+        parser.push('NOLOOP');
       }
     }
-
-    return args;
   },
+  transformArguments<M extends boolean>(
+    mode: M,
+    options?: M extends true ? ClientTrackingOptions : never
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/CLIENT_TRACKINGINFO.spec.ts b/packages/client/lib/commands/CLIENT_TRACKINGINFO.spec.ts
index 1cefbd27d53..d776519df22 100644
--- a/packages/client/lib/commands/CLIENT_TRACKINGINFO.spec.ts
+++ b/packages/client/lib/commands/CLIENT_TRACKINGINFO.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_TRACKINGINFO from './CLIENT_TRACKINGINFO';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT TRACKINGINFO', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_TRACKINGINFO.transformArguments(),
+      parseArgs(CLIENT_TRACKINGINFO),
       ['CLIENT', 'TRACKINGINFO']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_TRACKINGINFO.ts b/packages/client/lib/commands/CLIENT_TRACKINGINFO.ts
index d969ba0219e..f153ac6bb98 100644
--- a/packages/client/lib/commands/CLIENT_TRACKINGINFO.ts
+++ b/packages/client/lib/commands/CLIENT_TRACKINGINFO.ts
@@ -1,4 +1,5 @@
 import { TuplesToMapReply, BlobStringReply, SetReply, NumberReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type TrackingInfo = TuplesToMapReply<[
   [BlobStringReply<'flags'>, SetReply<BlobStringReply>],
@@ -9,9 +10,10 @@ type TrackingInfo = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLIENT', 'TRACKINGINFO'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'TRACKINGINFO']);
   },
+  transformArguments() { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<TrackingInfo>>) => ({
       flags: reply[1],
diff --git a/packages/client/lib/commands/CLIENT_UNPAUSE.spec.ts b/packages/client/lib/commands/CLIENT_UNPAUSE.spec.ts
index bddf3ca0f02..0b58cf6517e 100644
--- a/packages/client/lib/commands/CLIENT_UNPAUSE.spec.ts
+++ b/packages/client/lib/commands/CLIENT_UNPAUSE.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLIENT_UNPAUSE from './CLIENT_UNPAUSE';
+import { parseArgs } from './generic-transformers';
 
 describe('CLIENT UNPAUSE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      CLIENT_UNPAUSE.transformArguments(),
+      parseArgs(CLIENT_UNPAUSE),
       ['CLIENT', 'UNPAUSE']
     );
   });
diff --git a/packages/client/lib/commands/CLIENT_UNPAUSE.ts b/packages/client/lib/commands/CLIENT_UNPAUSE.ts
index 9da0a9a8bbe..b659fc19096 100644
--- a/packages/client/lib/commands/CLIENT_UNPAUSE.ts
+++ b/packages/client/lib/commands/CLIENT_UNPAUSE.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLIENT', 'UNPAUSE'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLIENT', 'UNPAUSE']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_ADDSLOTS.spec.ts b/packages/client/lib/commands/CLUSTER_ADDSLOTS.spec.ts
index 56f7b2a85e7..4a9b1839bb4 100644
--- a/packages/client/lib/commands/CLUSTER_ADDSLOTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_ADDSLOTS.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_ADDSLOTS from './CLUSTER_ADDSLOTS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER ADDSLOTS', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        CLUSTER_ADDSLOTS.transformArguments(0),
+        parseArgs(CLUSTER_ADDSLOTS, 0),
         ['CLUSTER', 'ADDSLOTS', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        CLUSTER_ADDSLOTS.transformArguments([0, 1]),
+        parseArgs(CLUSTER_ADDSLOTS, [0, 1]),
         ['CLUSTER', 'ADDSLOTS', '0', '1']
       );
     });
diff --git a/packages/client/lib/commands/CLUSTER_ADDSLOTS.ts b/packages/client/lib/commands/CLUSTER_ADDSLOTS.ts
index dc42c2f13e8..9089042a434 100644
--- a/packages/client/lib/commands/CLUSTER_ADDSLOTS.ts
+++ b/packages/client/lib/commands/CLUSTER_ADDSLOTS.ts
@@ -1,14 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
-import { pushVariadicNumberArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(slots: number | Array<number>) {
-    return pushVariadicNumberArguments(
-      ['CLUSTER', 'ADDSLOTS'],
-      slots
-    );
+  parseCommand(parser: CommandParser, slots: number | Array<number>) {
+    parser.pushVariadic(['CLUSTER', 'ADDSLOTS']);
+    parser.pushVariadicNumber(slots);
   },
+  transformArguments(slots: number | Array<number>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.spec.ts b/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.spec.ts
index 6af6f586e99..40706968f93 100644
--- a/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import CLUSTER_ADDSLOTSRANGE from './CLUSTER_ADDSLOTSRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER ADDSLOTSRANGE', () => {
   testUtils.isVersionGreaterThanHook([7, 0]);
@@ -8,7 +9,7 @@ describe('CLUSTER ADDSLOTSRANGE', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        CLUSTER_ADDSLOTSRANGE.transformArguments({
+        parseArgs(CLUSTER_ADDSLOTSRANGE, {
           start: 0,
           end: 1
         }),
@@ -18,7 +19,7 @@ describe('CLUSTER ADDSLOTSRANGE', () => {
 
     it('multiple', () => {
       assert.deepEqual(
-        CLUSTER_ADDSLOTSRANGE.transformArguments([{
+        parseArgs(CLUSTER_ADDSLOTSRANGE, [{
           start: 0,
           end: 1
         }, {
diff --git a/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.ts b/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.ts
index 5cf649a30da..97e5d380e55 100644
--- a/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.ts
+++ b/packages/client/lib/commands/CLUSTER_ADDSLOTSRANGE.ts
@@ -1,14 +1,14 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { pushSlotRangesArguments, SlotRange } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(ranges: SlotRange | Array<SlotRange>) {
-    return pushSlotRangesArguments(
-      ['CLUSTER', 'ADDSLOTSRANGE'],
-      ranges
-    );
+  parseCommand(parser: CommandParser, ranges: SlotRange | Array<SlotRange>) {
+    parser.pushVariadic(['CLUSTER', 'ADDSLOTSRANGE']);
+    pushSlotRangesArguments(parser, ranges);
   },
+  transformArguments(ranges: SlotRange | Array<SlotRange>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
index d21bc47c5d0..f3ecde9f6a8 100644
--- a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_BUMPEPOCH from './CLUSTER_BUMPEPOCH';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER BUMPEPOCH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_BUMPEPOCH.transformArguments(),
+      parseArgs(CLUSTER_BUMPEPOCH),
       ['CLUSTER', 'BUMPEPOCH']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.ts b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.ts
index 94f7e3b56f9..5371fd1363a 100644
--- a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.ts
+++ b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'BUMPEPOCH'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'BUMPEPOCH']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'BUMPED' | 'STILL'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
index 93c2aca7804..06a901ef301 100644
--- a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_COUNT_FAILURE_REPORTS from './CLUSTER_COUNT-FAILURE-REPORTS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER COUNT-FAILURE-REPORTS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_COUNT_FAILURE_REPORTS.transformArguments('0'),
+      parseArgs(CLUSTER_COUNT_FAILURE_REPORTS, '0'),
       ['CLUSTER', 'COUNT-FAILURE-REPORTS', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.ts b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.ts
index a005694713d..4f0911d7c1f 100644
--- a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(nodeId: RedisArgument) {
-    return ['CLUSTER', 'COUNT-FAILURE-REPORTS', nodeId];
+  parseCommand(parser: CommandParser, nodeId: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'COUNT-FAILURE-REPORTS', nodeId]);
   },
+  transformArguments(nodeId: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
index 180a120e153..52848409465 100644
--- a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_COUNTKEYSINSLOT from './CLUSTER_COUNTKEYSINSLOT';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER COUNTKEYSINSLOT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_COUNTKEYSINSLOT.transformArguments(0),
+      parseArgs(CLUSTER_COUNTKEYSINSLOT, 0),
       ['CLUSTER', 'COUNTKEYSINSLOT', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.ts b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.ts
index 61f46230e89..cffb845ec71 100644
--- a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(slot: number) {
-    return ['CLUSTER', 'COUNTKEYSINSLOT', slot.toString()];
+  parseCommand(parser: CommandParser, slot: number) {
+    parser.pushVariadic(['CLUSTER', 'COUNTKEYSINSLOT', slot.toString()]);
   },
+  transformArguments(slot: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_DELSLOTS.spec.ts b/packages/client/lib/commands/CLUSTER_DELSLOTS.spec.ts
index 59e40217b9c..2937fdd4d79 100644
--- a/packages/client/lib/commands/CLUSTER_DELSLOTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_DELSLOTS.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_DELSLOTS from './CLUSTER_DELSLOTS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER DELSLOTS', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        CLUSTER_DELSLOTS.transformArguments(0),
+        parseArgs(CLUSTER_DELSLOTS, 0),
         ['CLUSTER', 'DELSLOTS', '0']
       );
     });
 
     it('multiple', () => {
       assert.deepEqual(
-        CLUSTER_DELSLOTS.transformArguments([0, 1]),
+        parseArgs(CLUSTER_DELSLOTS, [0, 1]),
         ['CLUSTER', 'DELSLOTS', '0', '1']
       );
     });
diff --git a/packages/client/lib/commands/CLUSTER_DELSLOTS.ts b/packages/client/lib/commands/CLUSTER_DELSLOTS.ts
index 6a6bbb76085..d7b17a4fec9 100644
--- a/packages/client/lib/commands/CLUSTER_DELSLOTS.ts
+++ b/packages/client/lib/commands/CLUSTER_DELSLOTS.ts
@@ -1,14 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
-import { pushVariadicNumberArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(slots: number | Array<number>) {
-    return pushVariadicNumberArguments(
-      ['CLUSTER', 'DELSLOTS'],
-      slots
-    );
+  parseCommand(parser: CommandParser, slots: number | Array<number>) {
+    parser.pushVariadic(['CLUSTER', 'DELSLOTS']);
+    parser.pushVariadicNumber(slots);
   },
+  transformArguments(slots: number | Array<number>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.spec.ts b/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.spec.ts
index 2615f394b87..6007421d11b 100644
--- a/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_DELSLOTSRANGE from './CLUSTER_DELSLOTSRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER DELSLOTSRANGE', () => {
   describe('transformArguments', () => {
     it('single', () => {
       assert.deepEqual(
-        CLUSTER_DELSLOTSRANGE.transformArguments({
+        parseArgs(CLUSTER_DELSLOTSRANGE, {
           start: 0,
           end: 1
         }),
@@ -15,7 +16,7 @@ describe('CLUSTER DELSLOTSRANGE', () => {
 
     it('multiple', () => {
       assert.deepEqual(
-        CLUSTER_DELSLOTSRANGE.transformArguments([{
+        parseArgs(CLUSTER_DELSLOTSRANGE, [{
           start: 0,
           end: 1
         }, {
diff --git a/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.ts b/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.ts
index e28ca9c8405..e0240396760 100644
--- a/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.ts
+++ b/packages/client/lib/commands/CLUSTER_DELSLOTSRANGE.ts
@@ -1,14 +1,14 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { pushSlotRangesArguments, SlotRange } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(ranges: SlotRange | Array<SlotRange>) {
-    return pushSlotRangesArguments(
-      ['CLUSTER', 'DELSLOTSRANGE'],
-      ranges
-    );
+  parseCommand(parser:CommandParser, ranges: SlotRange | Array<SlotRange>) {
+    parser.pushVariadic(['CLUSTER', 'DELSLOTSRANGE']);
+    pushSlotRangesArguments(parser, ranges);
   },
+  transformArguments(ranges: SlotRange | Array<SlotRange>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_FAILOVER.spec.ts b/packages/client/lib/commands/CLUSTER_FAILOVER.spec.ts
index ac18a9a7f8f..f8e4b986048 100644
--- a/packages/client/lib/commands/CLUSTER_FAILOVER.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_FAILOVER.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_FAILOVER, { FAILOVER_MODES } from './CLUSTER_FAILOVER';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER FAILOVER', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLUSTER_FAILOVER.transformArguments(),
+        parseArgs(CLUSTER_FAILOVER),
         ['CLUSTER', 'FAILOVER']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        CLUSTER_FAILOVER.transformArguments({
+        parseArgs(CLUSTER_FAILOVER, {
           mode: FAILOVER_MODES.FORCE
         }),
         ['CLUSTER', 'FAILOVER', 'FORCE']
diff --git a/packages/client/lib/commands/CLUSTER_FAILOVER.ts b/packages/client/lib/commands/CLUSTER_FAILOVER.ts
index 63f79a246ba..088ac4d3e8b 100644
--- a/packages/client/lib/commands/CLUSTER_FAILOVER.ts
+++ b/packages/client/lib/commands/CLUSTER_FAILOVER.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const FAILOVER_MODES = {
   FORCE: 'FORCE',
@@ -14,14 +15,13 @@ export interface ClusterFailoverOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(options?: ClusterFailoverOptions) {
-    const args = ['CLUSTER', 'FAILOVER'];
+  parseCommand(parser:CommandParser, options?: ClusterFailoverOptions) {
+    parser.pushVariadic(['CLUSTER', 'FAILOVER']);
 
     if (options?.mode) {
-      args.push(options.mode);
+      parser.push(options.mode);
     }
-
-    return args;
   },
+  transformArguments(options?: ClusterFailoverOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.spec.ts b/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.spec.ts
index fbc4346136d..43701adfe6a 100644
--- a/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_FLUSHSLOTS from './CLUSTER_FLUSHSLOTS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER FLUSHSLOTS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_FLUSHSLOTS.transformArguments(),
+      parseArgs(CLUSTER_FLUSHSLOTS),
       ['CLUSTER', 'FLUSHSLOTS']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.ts b/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.ts
index 327ed7b7d17..7a32b7ea512 100644
--- a/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.ts
+++ b/packages/client/lib/commands/CLUSTER_FLUSHSLOTS.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'FLUSHSLOTS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'FLUSHSLOTS']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_FORGET.spec.ts b/packages/client/lib/commands/CLUSTER_FORGET.spec.ts
index a9a923b01ee..8d02374cf87 100644
--- a/packages/client/lib/commands/CLUSTER_FORGET.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_FORGET.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_FORGET from './CLUSTER_FORGET';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER FORGET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_FORGET.transformArguments('0'),
+      parseArgs(CLUSTER_FORGET, '0'),
       ['CLUSTER', 'FORGET', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_FORGET.ts b/packages/client/lib/commands/CLUSTER_FORGET.ts
index a51c039563b..0485c629555 100644
--- a/packages/client/lib/commands/CLUSTER_FORGET.ts
+++ b/packages/client/lib/commands/CLUSTER_FORGET.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(nodeId: RedisArgument) {
-    return ['CLUSTER', 'FORGET', nodeId];
+  parseCommand(parser: CommandParser, nodeId: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'FORGET', nodeId]);
   },
+  transformArguments(nodeId: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
index f1a4e2c3bcc..468eecc74a9 100644
--- a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_GETKEYSINSLOT from './CLUSTER_GETKEYSINSLOT';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER GETKEYSINSLOT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_GETKEYSINSLOT.transformArguments(0, 10),
+      parseArgs(CLUSTER_GETKEYSINSLOT, 0, 10),
       ['CLUSTER', 'GETKEYSINSLOT', '0', '10']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.ts b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.ts
index c19cd225e04..19e85dd5623 100644
--- a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.ts
+++ b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.ts
@@ -1,10 +1,12 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(slot: number, count: number) {
-    return ['CLUSTER', 'GETKEYSINSLOT', slot.toString(), count.toString()];
+  parseCommand(parser: CommandParser, slot: number, count: number) {
+    parser.pushVariadic(['CLUSTER', 'GETKEYSINSLOT', slot.toString(), count.toString()]);
   },
+  transformArguments(slot: number, count: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_INFO.spec.ts b/packages/client/lib/commands/CLUSTER_INFO.spec.ts
index f7c708663fc..01dafce8d53 100644
--- a/packages/client/lib/commands/CLUSTER_INFO.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_INFO.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_INFO from './CLUSTER_INFO';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER INFO', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_INFO.transformArguments(),
+      parseArgs(CLUSTER_INFO),
       ['CLUSTER', 'INFO']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_INFO.ts b/packages/client/lib/commands/CLUSTER_INFO.ts
index 4605efbe81a..9f788d4c2b1 100644
--- a/packages/client/lib/commands/CLUSTER_INFO.ts
+++ b/packages/client/lib/commands/CLUSTER_INFO.ts
@@ -1,10 +1,12 @@
 import { VerbatimStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'INFO'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'INFO']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => VerbatimStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
index d582c616cd1..188c403abb5 100644
--- a/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_KEYSLOT from './CLUSTER_KEYSLOT';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER KEYSLOT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_KEYSLOT.transformArguments('key'),
+      parseArgs(CLUSTER_KEYSLOT, 'key'),
       ['CLUSTER', 'KEYSLOT', 'key']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_KEYSLOT.ts b/packages/client/lib/commands/CLUSTER_KEYSLOT.ts
index 81e84430116..5d9a7d40a34 100644
--- a/packages/client/lib/commands/CLUSTER_KEYSLOT.ts
+++ b/packages/client/lib/commands/CLUSTER_KEYSLOT.ts
@@ -1,10 +1,12 @@
 import { Command, NumberReply, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['CLUSTER', 'KEYSLOT', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'KEYSLOT', key]);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_LINKS.spec.ts b/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
index d94231634e0..609ecfd3da9 100644
--- a/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_LINKS from './CLUSTER_LINKS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER LINKS', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_LINKS.transformArguments(),
+      parseArgs(CLUSTER_LINKS),
       ['CLUSTER', 'LINKS']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_LINKS.ts b/packages/client/lib/commands/CLUSTER_LINKS.ts
index df83f3f7a11..6136dc149ef 100644
--- a/packages/client/lib/commands/CLUSTER_LINKS.ts
+++ b/packages/client/lib/commands/CLUSTER_LINKS.ts
@@ -1,4 +1,5 @@
 import { ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type ClusterLinksReply = ArrayReply<TuplesToMapReply<[
   [BlobStringReply<'direction'>, BlobStringReply],
@@ -12,9 +13,10 @@ type ClusterLinksReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'LINKS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'LINKS']);
   },
+  transformArguments() { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<ClusterLinksReply>>) => reply.map(link => {
       const unwrapped = link as unknown as UnwrapReply<typeof link>;
diff --git a/packages/client/lib/commands/CLUSTER_MEET.spec.ts b/packages/client/lib/commands/CLUSTER_MEET.spec.ts
index 0b678f009f7..6c063f34e45 100644
--- a/packages/client/lib/commands/CLUSTER_MEET.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_MEET.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_MEET from './CLUSTER_MEET';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER MEET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_MEET.transformArguments('127.0.0.1', 6379),
+      parseArgs(CLUSTER_MEET, '127.0.0.1', 6379),
       ['CLUSTER', 'MEET', '127.0.0.1', '6379']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_MEET.ts b/packages/client/lib/commands/CLUSTER_MEET.ts
index df72599d40b..e48360a935b 100644
--- a/packages/client/lib/commands/CLUSTER_MEET.ts
+++ b/packages/client/lib/commands/CLUSTER_MEET.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(host: string, port: number) {
-    return ['CLUSTER', 'MEET', host, port.toString()];
+  parseCommand(parser: CommandParser, host: string, port: number) {
+    parser.pushVariadic(['CLUSTER', 'MEET', host, port.toString()]);
   },
+  transformArguments(host: string, port: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_MYID.spec.ts b/packages/client/lib/commands/CLUSTER_MYID.spec.ts
index 74540e98ab7..78bb4495e3c 100644
--- a/packages/client/lib/commands/CLUSTER_MYID.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_MYID.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_MYID from './CLUSTER_MYID';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER MYID', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_MYID.transformArguments(),
+      parseArgs(CLUSTER_MYID),
       ['CLUSTER', 'MYID']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_MYID.ts b/packages/client/lib/commands/CLUSTER_MYID.ts
index 73711b47ebb..c2d09945799 100644
--- a/packages/client/lib/commands/CLUSTER_MYID.ts
+++ b/packages/client/lib/commands/CLUSTER_MYID.ts
@@ -1,10 +1,12 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'MYID'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'MYID']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts b/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
index e64f2e3777a..6c2a61801bc 100644
--- a/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_MYSHARDID from './CLUSTER_MYSHARDID';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER MYSHARDID', () => {
   testUtils.isVersionGreaterThanHook([7, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_MYSHARDID.transformArguments(),
+      parseArgs(CLUSTER_MYSHARDID),
       ['CLUSTER', 'MYSHARDID']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_MYSHARDID.ts b/packages/client/lib/commands/CLUSTER_MYSHARDID.ts
index 0c38b61634f..f321b0142e2 100644
--- a/packages/client/lib/commands/CLUSTER_MYSHARDID.ts
+++ b/packages/client/lib/commands/CLUSTER_MYSHARDID.ts
@@ -1,11 +1,13 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'MYSHARDID'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'MYSHARDID']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/CLUSTER_NODES.spec.ts b/packages/client/lib/commands/CLUSTER_NODES.spec.ts
index 99db17a23e6..a49996586b7 100644
--- a/packages/client/lib/commands/CLUSTER_NODES.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_NODES.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_NODES from './CLUSTER_NODES';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER NODES', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_NODES.transformArguments(),
+      parseArgs(CLUSTER_NODES),
       ['CLUSTER', 'NODES']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_NODES.ts b/packages/client/lib/commands/CLUSTER_NODES.ts
index 64dd5056232..f87279d75e4 100644
--- a/packages/client/lib/commands/CLUSTER_NODES.ts
+++ b/packages/client/lib/commands/CLUSTER_NODES.ts
@@ -1,10 +1,12 @@
 import { VerbatimStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'NODES'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'NODES']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => VerbatimStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_REPLICAS.spec.ts b/packages/client/lib/commands/CLUSTER_REPLICAS.spec.ts
index 1a48f360885..11bf086bb66 100644
--- a/packages/client/lib/commands/CLUSTER_REPLICAS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_REPLICAS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_REPLICAS from './CLUSTER_REPLICAS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER REPLICAS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_REPLICAS.transformArguments('0'),
+      parseArgs(CLUSTER_REPLICAS, '0'),
       ['CLUSTER', 'REPLICAS', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_REPLICAS.ts b/packages/client/lib/commands/CLUSTER_REPLICAS.ts
index 8e0fe2cdfd9..0cc4bf53233 100644
--- a/packages/client/lib/commands/CLUSTER_REPLICAS.ts
+++ b/packages/client/lib/commands/CLUSTER_REPLICAS.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(nodeId: RedisArgument) {
-    return ['CLUSTER', 'REPLICAS', nodeId];
+  parseCommand(parser: CommandParser, nodeId: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'REPLICAS', nodeId]);
   },
+  transformArguments(nodeId: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_REPLICATE.spec.ts b/packages/client/lib/commands/CLUSTER_REPLICATE.spec.ts
index 80935385a88..3f130d360bf 100644
--- a/packages/client/lib/commands/CLUSTER_REPLICATE.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_REPLICATE.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_REPLICATE from './CLUSTER_REPLICATE';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER REPLICATE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_REPLICATE.transformArguments('0'),
+      parseArgs(CLUSTER_REPLICATE, '0'),
       ['CLUSTER', 'REPLICATE', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_REPLICATE.ts b/packages/client/lib/commands/CLUSTER_REPLICATE.ts
index 7431142024c..c1ee48d4927 100644
--- a/packages/client/lib/commands/CLUSTER_REPLICATE.ts
+++ b/packages/client/lib/commands/CLUSTER_REPLICATE.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(nodeId: RedisArgument) {
-    return ['CLUSTER', 'REPLICATE', nodeId];
+  parseCommand(parser: CommandParser, nodeId: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'REPLICATE', nodeId]);
   },
+  transformArguments(nodeId: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_RESET.spec.ts b/packages/client/lib/commands/CLUSTER_RESET.spec.ts
index 190bdaf69e1..1ef55e3f572 100644
--- a/packages/client/lib/commands/CLUSTER_RESET.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_RESET.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_RESET from './CLUSTER_RESET';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER RESET', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLUSTER_RESET.transformArguments(),
+        parseArgs(CLUSTER_RESET),
         ['CLUSTER', 'RESET']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        CLUSTER_RESET.transformArguments({
+        parseArgs(CLUSTER_RESET, {
           mode: 'HARD'
         }),
         ['CLUSTER', 'RESET', 'HARD']
diff --git a/packages/client/lib/commands/CLUSTER_RESET.ts b/packages/client/lib/commands/CLUSTER_RESET.ts
index 7aaac9d3b0d..7bca434d483 100644
--- a/packages/client/lib/commands/CLUSTER_RESET.ts
+++ b/packages/client/lib/commands/CLUSTER_RESET.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface ClusterResetOptions {
   mode?: 'HARD' | 'SOFT';
@@ -7,14 +8,13 @@ export interface ClusterResetOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(options?: ClusterResetOptions) {
-    const args = ['CLUSTER', 'RESET'];
+  parseCommand(parser: CommandParser, options?: ClusterResetOptions) {
+    parser.pushVariadic(['CLUSTER', 'RESET']);
 
     if (options?.mode) {
-      args.push(options.mode);
+      parser.push(options.mode);
     }
-
-    return args;
   },
+  transformArguments(options?: ClusterResetOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts b/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
index ece8087e8e4..a0d317ffae4 100644
--- a/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_SAVECONFIG from './CLUSTER_SAVECONFIG';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER SAVECONFIG', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_SAVECONFIG.transformArguments(),
+      parseArgs(CLUSTER_SAVECONFIG),
       ['CLUSTER', 'SAVECONFIG']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_SAVECONFIG.ts b/packages/client/lib/commands/CLUSTER_SAVECONFIG.ts
index 489ffd27e48..2477777787c 100644
--- a/packages/client/lib/commands/CLUSTER_SAVECONFIG.ts
+++ b/packages/client/lib/commands/CLUSTER_SAVECONFIG.ts
@@ -1,11 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'SAVECONFIG'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'SAVECONFIG']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.spec.ts b/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.spec.ts
index 39cf026d0ef..fb02ee2fe65 100644
--- a/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_SET_CONFIG_EPOCH from './CLUSTER_SET-CONFIG-EPOCH';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER SET-CONFIG-EPOCH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_SET_CONFIG_EPOCH.transformArguments(0),
+      parseArgs(CLUSTER_SET_CONFIG_EPOCH, 0),
       ['CLUSTER', 'SET-CONFIG-EPOCH', '0']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.ts b/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.ts
index 2a650840c44..5041cdabd75 100644
--- a/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.ts
+++ b/packages/client/lib/commands/CLUSTER_SET-CONFIG-EPOCH.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(configEpoch: number) {
-    return ['CLUSTER', 'SET-CONFIG-EPOCH', configEpoch.toString() ];
+  parseCommand(parser: CommandParser, configEpoch: number) {
+    parser.pushVariadic(['CLUSTER', 'SET-CONFIG-EPOCH', configEpoch.toString()]);
   },
+  transformArguments(configEpoch: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_SETSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_SETSLOT.spec.ts
index 7bce6d74b4a..fac496c3afb 100644
--- a/packages/client/lib/commands/CLUSTER_SETSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_SETSLOT.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import CLUSTER_SETSLOT, { CLUSTER_SLOT_STATES } from './CLUSTER_SETSLOT';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER SETSLOT', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLUSTER_SETSLOT.transformArguments(0, CLUSTER_SLOT_STATES.IMPORTING),
+        parseArgs(CLUSTER_SETSLOT, 0, CLUSTER_SLOT_STATES.IMPORTING),
         ['CLUSTER', 'SETSLOT', '0', 'IMPORTING']
       );
     });
 
     it('with nodeId', () => {
       assert.deepEqual(
-        CLUSTER_SETSLOT.transformArguments(0, CLUSTER_SLOT_STATES.IMPORTING, 'nodeId'),
+        parseArgs(CLUSTER_SETSLOT, 0, CLUSTER_SLOT_STATES.IMPORTING, 'nodeId'),
         ['CLUSTER', 'SETSLOT', '0', 'IMPORTING', 'nodeId']
       );
     });
diff --git a/packages/client/lib/commands/CLUSTER_SETSLOT.ts b/packages/client/lib/commands/CLUSTER_SETSLOT.ts
index ad04513688e..d24c46208dd 100644
--- a/packages/client/lib/commands/CLUSTER_SETSLOT.ts
+++ b/packages/client/lib/commands/CLUSTER_SETSLOT.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const CLUSTER_SLOT_STATES = {
   IMPORTING: 'IMPORTING',
@@ -12,14 +13,13 @@ export type ClusterSlotState = typeof CLUSTER_SLOT_STATES[keyof typeof CLUSTER_S
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(slot: number, state: ClusterSlotState, nodeId?: RedisArgument) {
-    const args: Array<RedisArgument> = ['CLUSTER', 'SETSLOT', slot.toString(), state];
+  parseCommand(parser: CommandParser, slot: number, state: ClusterSlotState, nodeId?: RedisArgument) {
+    parser.pushVariadic(['CLUSTER', 'SETSLOT', slot.toString(), state]);
 
     if (nodeId) {
-      args.push(nodeId);
+      parser.push(nodeId);
     }
-
-    return args;
   },
+  transformArguments(slot: number, state: ClusterSlotState, nodeId?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CLUSTER_SLOTS.spec.ts b/packages/client/lib/commands/CLUSTER_SLOTS.spec.ts
index 198dfdc6c1b..28879b036ae 100644
--- a/packages/client/lib/commands/CLUSTER_SLOTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_SLOTS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLUSTER_SLOTS from './CLUSTER_SLOTS';
+import { parseArgs } from './generic-transformers';
 
 describe('CLUSTER SLOTS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CLUSTER_SLOTS.transformArguments(),
+      parseArgs(CLUSTER_SLOTS),
       ['CLUSTER', 'SLOTS']
     );
   });
diff --git a/packages/client/lib/commands/CLUSTER_SLOTS.ts b/packages/client/lib/commands/CLUSTER_SLOTS.ts
index 1b523328bbb..5d90ba585fc 100644
--- a/packages/client/lib/commands/CLUSTER_SLOTS.ts
+++ b/packages/client/lib/commands/CLUSTER_SLOTS.ts
@@ -1,4 +1,5 @@
 import { TuplesReply, BlobStringReply, NumberReply, ArrayReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type RawNode = TuplesReply<[
   host: BlobStringReply,
@@ -18,9 +19,10 @@ export type ClusterSlotsNode = ReturnType<typeof transformNode>;
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CLUSTER', 'SLOTS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CLUSTER', 'SLOTS']);
   },
+  transformArguments() { return [] },
   transformReply(reply: UnwrapReply<ClusterSlotsRawReply>) {
     return reply.map(([from, to, master, ...replicas]) => ({
       from,
diff --git a/packages/client/lib/commands/COMMAND_COUNT.spec.ts b/packages/client/lib/commands/COMMAND_COUNT.spec.ts
index 05bd29f223c..a36091df482 100644
--- a/packages/client/lib/commands/COMMAND_COUNT.spec.ts
+++ b/packages/client/lib/commands/COMMAND_COUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import COMMAND_COUNT from './COMMAND_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('COMMAND COUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      COMMAND_COUNT.transformArguments(),
+      parseArgs(COMMAND_COUNT),
       ['COMMAND', 'COUNT']
     );
   });
diff --git a/packages/client/lib/commands/COMMAND_COUNT.ts b/packages/client/lib/commands/COMMAND_COUNT.ts
index 10b0fdefe09..e6d86d553ab 100644
--- a/packages/client/lib/commands/COMMAND_COUNT.ts
+++ b/packages/client/lib/commands/COMMAND_COUNT.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['COMMAND', 'COUNT'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['COMMAND', 'COUNT']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/COMMAND_GETKEYS.spec.ts b/packages/client/lib/commands/COMMAND_GETKEYS.spec.ts
index d5b9f60790d..332e2d51fbd 100644
--- a/packages/client/lib/commands/COMMAND_GETKEYS.spec.ts
+++ b/packages/client/lib/commands/COMMAND_GETKEYS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import COMMAND_GETKEYS from './COMMAND_GETKEYS';
+import { parseArgs } from './generic-transformers';
 
 describe('COMMAND GETKEYS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      COMMAND_GETKEYS.transformArguments(['GET', 'key']),
+      parseArgs(COMMAND_GETKEYS, ['GET', 'key']),
       ['COMMAND', 'GETKEYS', 'GET', 'key']
     );
   });
diff --git a/packages/client/lib/commands/COMMAND_GETKEYS.ts b/packages/client/lib/commands/COMMAND_GETKEYS.ts
index 55cca415b8d..266c77fe888 100644
--- a/packages/client/lib/commands/COMMAND_GETKEYS.ts
+++ b/packages/client/lib/commands/COMMAND_GETKEYS.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(args: Array<RedisArgument>) {
-    return ['COMMAND', 'GETKEYS', ...args];
+  parseCommand(parser: CommandParser, args: Array<RedisArgument>) {
+    parser.pushVariadic(['COMMAND', 'GETKEYS', ...args]);
   },
+  transformArguments(args: Array<RedisArgument>) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts b/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts
index a032190c16e..34dcc19a656 100644
--- a/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts
+++ b/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, SetReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type CommandGetKeysAndFlagsRawReply = ArrayReply<TuplesReply<[
   key: BlobStringReply,
@@ -8,9 +9,10 @@ export type CommandGetKeysAndFlagsRawReply = ArrayReply<TuplesReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(args: Array<RedisArgument>) {
-    return ['COMMAND', 'GETKEYSANDFLAGS', ...args];
+  parseCommand(parser: CommandParser, args: Array<RedisArgument>) {
+    parser.pushVariadic(['COMMAND', 'GETKEYSANDFLAGS', ...args]);
   },
+  transformArguments(args: Array<RedisArgument>) { return [] },
   transformReply(reply: UnwrapReply<CommandGetKeysAndFlagsRawReply>) {
     return reply.map(entry => {
       const [key, flags] = entry as unknown as UnwrapReply<typeof entry>;
diff --git a/packages/client/lib/commands/COMMAND_LIST.spec.ts b/packages/client/lib/commands/COMMAND_LIST.spec.ts
index 28a9a203bc8..d2ee9e66161 100644
--- a/packages/client/lib/commands/COMMAND_LIST.spec.ts
+++ b/packages/client/lib/commands/COMMAND_LIST.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import COMMAND_LIST from './COMMAND_LIST';
+import { parseArgs } from './generic-transformers';
 
 describe('COMMAND LIST', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,7 +9,7 @@ describe('COMMAND LIST', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        COMMAND_LIST.transformArguments(),
+        parseArgs(COMMAND_LIST),
         ['COMMAND', 'LIST']
       );
     });
@@ -16,7 +17,7 @@ describe('COMMAND LIST', () => {
     describe('with FILTERBY', () => {
       it('MODULE', () => {
         assert.deepEqual(
-          COMMAND_LIST.transformArguments({
+          parseArgs(COMMAND_LIST, {
             FILTERBY: {
               type: 'MODULE',
               value: 'JSON'
@@ -28,7 +29,7 @@ describe('COMMAND LIST', () => {
 
       it('ACLCAT', () => {
         assert.deepEqual(
-          COMMAND_LIST.transformArguments({
+          parseArgs(COMMAND_LIST, {
             FILTERBY: {
               type: 'ACLCAT',
               value: 'admin'
@@ -40,7 +41,7 @@ describe('COMMAND LIST', () => {
 
       it('PATTERN', () => {
         assert.deepEqual(
-          COMMAND_LIST.transformArguments({
+          parseArgs(COMMAND_LIST, {
             FILTERBY: {
               type: 'PATTERN',
               value: 'a*'
diff --git a/packages/client/lib/commands/COMMAND_LIST.ts b/packages/client/lib/commands/COMMAND_LIST.ts
index e73cfdc1a0b..8a596b3884e 100644
--- a/packages/client/lib/commands/COMMAND_LIST.ts
+++ b/packages/client/lib/commands/COMMAND_LIST.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const COMMAND_LIST_FILTER_BY = {
   MODULE: 'MODULE',
@@ -18,18 +19,19 @@ export interface CommandListOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(options?: CommandListOptions) {
-    const args: Array<RedisArgument> = ['COMMAND', 'LIST'];
+  parseCommand(parser: CommandParser, options?: CommandListOptions) {
+    parser.pushVariadic(['COMMAND', 'LIST']);
 
     if (options?.FILTERBY) {
-      args.push(
-        'FILTERBY',
-        options.FILTERBY.type,
-        options.FILTERBY.value
+      parser.pushVariadic(
+        [
+          'FILTERBY',
+          options.FILTERBY.type,
+          options.FILTERBY.value
+        ]
       );
     }
-
-    return args;
   },
+  transformArguments(options?: CommandListOptions) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CONFIG_GET.spec.ts b/packages/client/lib/commands/CONFIG_GET.spec.ts
index 94bb2fadcb9..411b2ddf472 100644
--- a/packages/client/lib/commands/CONFIG_GET.spec.ts
+++ b/packages/client/lib/commands/CONFIG_GET.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CONFIG_GET from './CONFIG_GET';
+import { parseArgs } from './generic-transformers';
 
 describe('CONFIG GET', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        CONFIG_GET.transformArguments('*'),
+        parseArgs(CONFIG_GET, '*'),
         ['CONFIG', 'GET', '*']
       );
     });
 
     it('Array', () => {
       assert.deepEqual(
-        CONFIG_GET.transformArguments(['1', '2']),
+        parseArgs(CONFIG_GET, ['1', '2']),
         ['CONFIG', 'GET', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/CONFIG_GET.ts b/packages/client/lib/commands/CONFIG_GET.ts
index 72fb6e56f5f..5ebee995fe3 100644
--- a/packages/client/lib/commands/CONFIG_GET.ts
+++ b/packages/client/lib/commands/CONFIG_GET.ts
@@ -1,12 +1,15 @@
 import { MapReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments, transformTuplesReply } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument, transformTuplesReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(parameters: RedisVariadicArgument) {
-    return pushVariadicArguments(['CONFIG', 'GET'], parameters);
+  parseCommand(parser: CommandParser, parameters: RedisVariadicArgument) {
+    parser.pushVariadic(['CONFIG', 'GET']);
+    parser.pushVariadic(parameters);
   },
+  transformArguments(parameters: RedisVariadicArgument) { return [] },
   transformReply: {
     2: transformTuplesReply,
     3: undefined as unknown as () => MapReply<BlobStringReply, BlobStringReply>
diff --git a/packages/client/lib/commands/CONFIG_RESETSTAT.spec.ts b/packages/client/lib/commands/CONFIG_RESETSTAT.spec.ts
index c0699e182fc..f2f573df0dc 100644
--- a/packages/client/lib/commands/CONFIG_RESETSTAT.spec.ts
+++ b/packages/client/lib/commands/CONFIG_RESETSTAT.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CONFIG_RESETSTAT from './CONFIG_RESETSTAT';
+import { parseArgs } from './generic-transformers';
 
 describe('CONFIG RESETSTAT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CONFIG_RESETSTAT.transformArguments(),
+      parseArgs(CONFIG_RESETSTAT),
       ['CONFIG', 'RESETSTAT']
     );
   });
diff --git a/packages/client/lib/commands/CONFIG_RESETSTAT.ts b/packages/client/lib/commands/CONFIG_RESETSTAT.ts
index 4d5deb18b47..0979b46bf52 100644
--- a/packages/client/lib/commands/CONFIG_RESETSTAT.ts
+++ b/packages/client/lib/commands/CONFIG_RESETSTAT.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CONFIG', 'RESETSTAT'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CONFIG', 'RESETSTAT']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CONFIG_REWRITE.spec.ts b/packages/client/lib/commands/CONFIG_REWRITE.spec.ts
index d612ae216bc..bc006e84c80 100644
--- a/packages/client/lib/commands/CONFIG_REWRITE.spec.ts
+++ b/packages/client/lib/commands/CONFIG_REWRITE.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import CONFIG_REWRITE from './CONFIG_REWRITE';
+import { parseArgs } from './generic-transformers';
 
 describe('CONFIG REWRITE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CONFIG_REWRITE.transformArguments(),
+      parseArgs(CONFIG_REWRITE),
       ['CONFIG', 'REWRITE']
     );
   });
diff --git a/packages/client/lib/commands/CONFIG_REWRITE.ts b/packages/client/lib/commands/CONFIG_REWRITE.ts
index 6fbc4b1fa27..8b7c6c29afc 100644
--- a/packages/client/lib/commands/CONFIG_REWRITE.ts
+++ b/packages/client/lib/commands/CONFIG_REWRITE.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['CONFIG', 'REWRITE'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['CONFIG', 'REWRITE']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/CONFIG_SET.spec.ts b/packages/client/lib/commands/CONFIG_SET.spec.ts
index 060183f58d1..56bed2ac46a 100644
--- a/packages/client/lib/commands/CONFIG_SET.spec.ts
+++ b/packages/client/lib/commands/CONFIG_SET.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CONFIG_SET from './CONFIG_SET';
+import { parseArgs } from './generic-transformers';
 
 describe('CONFIG SET', () => {
   describe('transformArguments', () => {
     it('set one parameter (old version)', () => {
       assert.deepEqual(
-        CONFIG_SET.transformArguments('parameter', 'value'),
+        parseArgs(CONFIG_SET, 'parameter', 'value'),
         ['CONFIG', 'SET', 'parameter', 'value']
       );
     });
 
     it('set muiltiple parameters', () => {
       assert.deepEqual(
-        CONFIG_SET.transformArguments({
+        parseArgs(CONFIG_SET, {
           1: 'a',
           2: 'b',
           3: 'c'
diff --git a/packages/client/lib/commands/CONFIG_SET.ts b/packages/client/lib/commands/CONFIG_SET.ts
index c7072245e22..9dcb13795dd 100644
--- a/packages/client/lib/commands/CONFIG_SET.ts
+++ b/packages/client/lib/commands/CONFIG_SET.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type SingleParameter = [parameter: RedisArgument, value: RedisArgument];
 
@@ -7,20 +8,22 @@ type MultipleParameters = [config: Record<string, RedisArgument>];
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     ...[parameterOrConfig, value]: SingleParameter | MultipleParameters
   ) {
-    const args: Array<RedisArgument> = ['CONFIG', 'SET'];
+    parser.pushVariadic(['CONFIG', 'SET']);
   
     if (typeof parameterOrConfig === 'string' || parameterOrConfig instanceof Buffer) {
-      args.push(parameterOrConfig, value!);
+      parser.pushVariadic([parameterOrConfig, value!]);
     } else {
       for (const [key, value] of Object.entries(parameterOrConfig)) {
-        args.push(key, value);
+        parser.pushVariadic([key, value]);
       }
     }
-  
-    return args;
   },
+  transformArguments(
+    ...[parameterOrConfig, value]: SingleParameter | MultipleParameters
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/COPY.spec.ts b/packages/client/lib/commands/COPY.spec.ts
index c4c26c30dc2..cd0c6ec9fbe 100644
--- a/packages/client/lib/commands/COPY.spec.ts
+++ b/packages/client/lib/commands/COPY.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import COPY from './COPY';
+import { parseArgs } from './generic-transformers';
 
 describe('COPY', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('COPY', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        COPY.transformArguments('source', 'destination'),
+        parseArgs(COPY, 'source', 'destination'),
         ['COPY', 'source', 'destination']
       );
     });
 
     it('with destination DB flag', () => {
       assert.deepEqual(
-        COPY.transformArguments('source', 'destination', {
+        parseArgs(COPY, 'source', 'destination', {
           DB: 1
         }),
         ['COPY', 'source', 'destination', 'DB', '1']
@@ -24,7 +25,7 @@ describe('COPY', () => {
 
     it('with replace flag', () => {
       assert.deepEqual(
-        COPY.transformArguments('source', 'destination', {
+        parseArgs(COPY, 'source', 'destination', {
           REPLACE: true
         }),
         ['COPY', 'source', 'destination', 'REPLACE']
@@ -33,7 +34,7 @@ describe('COPY', () => {
 
     it('with both flags', () => {
       assert.deepEqual(
-        COPY.transformArguments('source', 'destination', {
+        parseArgs(COPY, 'source', 'destination', {
           DB: 1,
           REPLACE: true
         }),
diff --git a/packages/client/lib/commands/COPY.ts b/packages/client/lib/commands/COPY.ts
index a65948cf944..c5b0d98d08d 100644
--- a/packages/client/lib/commands/COPY.ts
+++ b/packages/client/lib/commands/COPY.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface CopyCommandOptions {
   DB?: number;
@@ -8,18 +9,17 @@ export interface CopyCommandOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(source: RedisArgument, destination: RedisArgument, options?: CopyCommandOptions) {
-    const args = ['COPY', source, destination];
+  parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument, options?: CopyCommandOptions) {
+    parser.pushVariadic(['COPY', source, destination]);
 
     if (options?.DB) {
-      args.push('DB', options.DB.toString());
+      parser.pushVariadic(['DB', options.DB.toString()]);
     }
 
     if (options?.REPLACE) {
-      args.push('REPLACE');
+      parser.push('REPLACE');
     }
-
-    return args;
   },
+  transformArguments(source: RedisArgument, destination: RedisArgument, options?: CopyCommandOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DBSIZE.spec.ts b/packages/client/lib/commands/DBSIZE.spec.ts
index bd668d166e7..5778e30de3e 100644
--- a/packages/client/lib/commands/DBSIZE.spec.ts
+++ b/packages/client/lib/commands/DBSIZE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DBSIZE from './DBSIZE';
+import { parseArgs } from './generic-transformers';
 
 describe('DBSIZE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      DBSIZE.transformArguments(),
+      parseArgs(DBSIZE),
       ['DBSIZE']
     );
   });
diff --git a/packages/client/lib/commands/DBSIZE.ts b/packages/client/lib/commands/DBSIZE.ts
index 54770831ab0..89d7e540cc2 100644
--- a/packages/client/lib/commands/DBSIZE.ts
+++ b/packages/client/lib/commands/DBSIZE.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['DBSIZE'];
+  parseCommand(parser: CommandParser) {
+    parser.push('DBSIZE');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DECR.spec.ts b/packages/client/lib/commands/DECR.spec.ts
index 80d6c8eb55e..69ff5a5391f 100644
--- a/packages/client/lib/commands/DECR.spec.ts
+++ b/packages/client/lib/commands/DECR.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DECR from './DECR';
+import { parseArgs } from './generic-transformers';
 
 describe('DECR', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      DECR.transformArguments('key'),
+      parseArgs(DECR, 'key'),
       ['DECR', 'key']
     );
   });
diff --git a/packages/client/lib/commands/DECR.ts b/packages/client/lib/commands/DECR.ts
index 540148b7eed..f65f3d8069b 100644
--- a/packages/client/lib/commands/DECR.ts
+++ b/packages/client/lib/commands/DECR.ts
@@ -1,9 +1,12 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument) {
-    return ['DECR', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('DECR');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DECRBY.spec.ts b/packages/client/lib/commands/DECRBY.spec.ts
index fc0c1033187..ae80fd714e0 100644
--- a/packages/client/lib/commands/DECRBY.spec.ts
+++ b/packages/client/lib/commands/DECRBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DECRBY from './DECRBY';
+import { parseArgs } from './generic-transformers';
 
 describe('DECRBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      DECRBY.transformArguments('key', 2),
+      parseArgs(DECRBY, 'key', 2),
       ['DECRBY', 'key', '2']
     );
   });
diff --git a/packages/client/lib/commands/DECRBY.ts b/packages/client/lib/commands/DECRBY.ts
index 77d56939dd5..85bc1612519 100644
--- a/packages/client/lib/commands/DECRBY.ts
+++ b/packages/client/lib/commands/DECRBY.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, decrement: number) {
-    return ['DECRBY', key, decrement.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, decrement: number) {
+    parser.push('DECRBY');
+    parser.pushKey(key);
+    parser.push(decrement.toString());
   },
+  transformArguments(key: RedisArgument, decrement: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DEL.spec.ts b/packages/client/lib/commands/DEL.spec.ts
index caac8ac13b5..3d0364e7523 100644
--- a/packages/client/lib/commands/DEL.spec.ts
+++ b/packages/client/lib/commands/DEL.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DEL from './DEL';
+import { parseArgs } from './generic-transformers';
 
 describe('DEL', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        DEL.transformArguments('key'),
+        parseArgs(DEL, 'key'),
         ['DEL', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        DEL.transformArguments(['key1', 'key2']),
+        parseArgs(DEL, ['key1', 'key2']),
         ['DEL', 'key1', 'key2']
       );
     });
diff --git a/packages/client/lib/commands/DEL.ts b/packages/client/lib/commands/DEL.ts
index f59a5ba2e89..c6b530fd791 100644
--- a/packages/client/lib/commands/DEL.ts
+++ b/packages/client/lib/commands/DEL.ts
@@ -1,11 +1,14 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['DEL'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.push('DEL');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DISCARD.spec.ts b/packages/client/lib/commands/DISCARD.spec.ts
index 76e0abd57af..7aa769fc2ee 100644
--- a/packages/client/lib/commands/DISCARD.spec.ts
+++ b/packages/client/lib/commands/DISCARD.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import DISCARD from './DISCARD';
+import { parseArgs } from './generic-transformers';
 
 describe('DISCARD', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      DISCARD.transformArguments(),
+      parseArgs(DISCARD),
       ['DISCARD']
     );
   });
diff --git a/packages/client/lib/commands/DISCARD.ts b/packages/client/lib/commands/DISCARD.ts
index e153070c989..cd7104b2192 100644
--- a/packages/client/lib/commands/DISCARD.ts
+++ b/packages/client/lib/commands/DISCARD.ts
@@ -1,8 +1,10 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
-  transformArguments() {
-    return ['DISCARD'];
+  parseCommand(parser: CommandParser) {
+    parser.push('DISCARD');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/DUMP.spec.ts b/packages/client/lib/commands/DUMP.spec.ts
index 15be3fae086..76fb2ec7c18 100644
--- a/packages/client/lib/commands/DUMP.spec.ts
+++ b/packages/client/lib/commands/DUMP.spec.ts
@@ -1,7 +1,16 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import DUMP from './DUMP';
+import { parseArgs } from './generic-transformers';
 
 describe('DUMP', () => {
+  it('transformArguments', () => {
+    assert.deepEqual(
+      parseArgs(DUMP, 'key'),
+      ['DUMP', 'key']
+    );
+  });
+
   testUtils.testAll('client.dump', async client => {
     assert.equal(
       await client.dump('key'),
diff --git a/packages/client/lib/commands/DUMP.ts b/packages/client/lib/commands/DUMP.ts
index 06b12f06d09..c09db6117db 100644
--- a/packages/client/lib/commands/DUMP.ts
+++ b/packages/client/lib/commands/DUMP.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['DUMP', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('DUMP');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ECHO.spec.ts b/packages/client/lib/commands/ECHO.spec.ts
index c0d0725282c..38fd1d4270e 100644
--- a/packages/client/lib/commands/ECHO.spec.ts
+++ b/packages/client/lib/commands/ECHO.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ECHO from './ECHO';
+import { parseArgs } from './generic-transformers';
 
 describe('ECHO', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ECHO.transformArguments('message'),
+      parseArgs(ECHO, 'message'),
       ['ECHO', 'message']
     );
   });
diff --git a/packages/client/lib/commands/ECHO.ts b/packages/client/lib/commands/ECHO.ts
index dfe5ec13000..3df6c5dbdf6 100644
--- a/packages/client/lib/commands/ECHO.ts
+++ b/packages/client/lib/commands/ECHO.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(message: RedisArgument) {
-    return ['ECHO', message];
+  parseCommand(parser: CommandParser, message: RedisArgument) {
+    parser.pushVariadic(['ECHO', message]);
   },
+  transformArguments(message: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EVAL.spec.ts b/packages/client/lib/commands/EVAL.spec.ts
index 2aea64e0991..8ef16eed835 100644
--- a/packages/client/lib/commands/EVAL.spec.ts
+++ b/packages/client/lib/commands/EVAL.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EVAL from './EVAL';
+import { parseArgs } from './generic-transformers';
 
 describe('EVAL', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      EVAL.transformArguments('return KEYS[1] + ARGV[1]', {
+      parseArgs(EVAL, 'return KEYS[1] + ARGV[1]', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/EVAL.ts b/packages/client/lib/commands/EVAL.ts
index 21684e7a313..c0636c955a7 100644
--- a/packages/client/lib/commands/EVAL.ts
+++ b/packages/client/lib/commands/EVAL.ts
@@ -1,33 +1,39 @@
 import { RedisArgument, ReplyUnion, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface EvalOptions {
   keys?: Array<RedisArgument>;
   arguments?: Array<RedisArgument>;
 }
 
-export function transformEvalArguments(
+export function parseEvalArguments(
   command: RedisArgument,
+  parser: CommandParser,
   script: RedisArgument,
   options?: EvalOptions
 ) {
-  const args = [command, script];
-
+  parser.pushVariadic([command, script]);
   if (options?.keys) {
-    args.push(options.keys.length.toString(), ...options.keys);
+    parser.pushKeysLength(options.keys);
   } else {
-    args.push('0');
+    parser.push('0');
   }
 
   if (options?.arguments) {
-    args.push(...options.arguments);
+    parser.pushVariadic(options.arguments)
   }
-
-  return args;
 }
 
+export function transformEvalArguments(
+  command: RedisArgument,
+  script: RedisArgument,
+  options?: EvalOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: (_, options?: EvalOptions) => options?.keys?.[0],
   IS_READ_ONLY: false,
+  parseCommand: parseEvalArguments.bind(undefined, 'EVAL'),
   transformArguments: transformEvalArguments.bind(undefined, 'EVAL'),
   transformReply: undefined as unknown as () => ReplyUnion
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EVALSHA.spec.ts b/packages/client/lib/commands/EVALSHA.spec.ts
index 81d3a0ec2b0..c491d6e2308 100644
--- a/packages/client/lib/commands/EVALSHA.spec.ts
+++ b/packages/client/lib/commands/EVALSHA.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import EVALSHA from './EVALSHA';
+import { parseArgs } from './generic-transformers';
 
 describe('EVALSHA', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      EVALSHA.transformArguments('sha1', {
+      parseArgs(EVALSHA, 'sha1', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/EVALSHA.ts b/packages/client/lib/commands/EVALSHA.ts
index dc4127f90da..86244eca9ba 100644
--- a/packages/client/lib/commands/EVALSHA.ts
+++ b/packages/client/lib/commands/EVALSHA.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import EVAL, { transformEvalArguments } from './EVAL';
+import EVAL, { parseEvalArguments, transformEvalArguments } from './EVAL';
 
 export default {
   FIRST_KEY_INDEX: EVAL.FIRST_KEY_INDEX,
   IS_READ_ONLY: false,
+  parseCommand: parseEvalArguments.bind(undefined, 'EVALSHA'),
   transformArguments: transformEvalArguments.bind(undefined, 'EVALSHA'),
   transformReply: EVAL.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EVALSHA_RO.spec.ts b/packages/client/lib/commands/EVALSHA_RO.spec.ts
index 20b4a27e0d1..d3debe933fe 100644
--- a/packages/client/lib/commands/EVALSHA_RO.spec.ts
+++ b/packages/client/lib/commands/EVALSHA_RO.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import EVALSHA_RO from './EVALSHA_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('EVALSHA_RO', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      EVALSHA_RO.transformArguments('sha1', {
+      parseArgs(EVALSHA_RO, 'sha1', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/EVALSHA_RO.ts b/packages/client/lib/commands/EVALSHA_RO.ts
index fe9042bd5fd..ab160a86b20 100644
--- a/packages/client/lib/commands/EVALSHA_RO.ts
+++ b/packages/client/lib/commands/EVALSHA_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import EVAL, { transformEvalArguments } from './EVAL';
+import EVAL, { parseEvalArguments, transformEvalArguments } from './EVAL';
 
 export default {
   FIRST_KEY_INDEX: EVAL.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseEvalArguments.bind(undefined, 'EVALSHA_RO'),
   transformArguments: transformEvalArguments.bind(undefined, 'EVALSHA_RO'),
   transformReply: EVAL.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EVAL_RO.spec.ts b/packages/client/lib/commands/EVAL_RO.spec.ts
index 3f071e80681..b5cf1e4e926 100644
--- a/packages/client/lib/commands/EVAL_RO.spec.ts
+++ b/packages/client/lib/commands/EVAL_RO.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EVAL_RO from './EVAL_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('EVAL_RO', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      EVAL_RO.transformArguments('return KEYS[1] + ARGV[1]', {
+      parseArgs(EVAL_RO, 'return KEYS[1] + ARGV[1]', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/EVAL_RO.ts b/packages/client/lib/commands/EVAL_RO.ts
index 2608e28f789..2cc9f4bf948 100644
--- a/packages/client/lib/commands/EVAL_RO.ts
+++ b/packages/client/lib/commands/EVAL_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import EVAL, { transformEvalArguments } from './EVAL';
+import EVAL, { parseEvalArguments, transformEvalArguments } from './EVAL';
 
 export default {
   FIRST_KEY_INDEX: EVAL.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseEvalArguments.bind(undefined, 'EVAL_RO'),
   transformArguments: transformEvalArguments.bind(undefined, 'EVAL_RO'),
   transformReply: EVAL.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EXISTS.spec.ts b/packages/client/lib/commands/EXISTS.spec.ts
index 695795697f1..d2802dd49b3 100644
--- a/packages/client/lib/commands/EXISTS.spec.ts
+++ b/packages/client/lib/commands/EXISTS.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EXISTS from './EXISTS';
+import { parseArgs } from './generic-transformers';
 
 describe('EXISTS', () => {
-  describe('transformArguments', () => {
+  describe('parseCommand', () => {
     it('string', () => {
       assert.deepEqual(
-        EXISTS.transformArguments('key'),
+        parseArgs(EXISTS, 'key'),
         ['EXISTS', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        EXISTS.transformArguments(['1', '2']),
+        parseArgs(EXISTS, ['1', '2']),
         ['EXISTS', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/EXISTS.ts b/packages/client/lib/commands/EXISTS.ts
index a077943b8d2..56215fe9544 100644
--- a/packages/client/lib/commands/EXISTS.ts
+++ b/packages/client/lib/commands/EXISTS.ts
@@ -1,11 +1,15 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['EXISTS'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('EXISTS');
+    parser.pushVariadic(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EXPIRE.spec.ts b/packages/client/lib/commands/EXPIRE.spec.ts
index 817e37cca45..f3d197b5c69 100644
--- a/packages/client/lib/commands/EXPIRE.spec.ts
+++ b/packages/client/lib/commands/EXPIRE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EXPIRE from './EXPIRE';
+import { parseArgs } from './generic-transformers';
 
 describe('EXPIRE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        EXPIRE.transformArguments('key', 1),
+        parseArgs(EXPIRE, 'key', 1),
         ['EXPIRE', 'key', '1']
       );
     });
 
     it('with set option', () => {
       assert.deepEqual(
-        EXPIRE.transformArguments('key', 1, 'NX'),
+        parseArgs(EXPIRE, 'key', 1, 'NX'),
         ['EXPIRE', 'key', '1', 'NX']
       );
     });
diff --git a/packages/client/lib/commands/EXPIRE.ts b/packages/client/lib/commands/EXPIRE.ts
index 3e57769bd6e..b1f9fcad35c 100644
--- a/packages/client/lib/commands/EXPIRE.ts
+++ b/packages/client/lib/commands/EXPIRE.ts
@@ -1,20 +1,26 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     seconds: number,
     mode?: 'NX' | 'XX' | 'GT' | 'LT'
   ) {
-    const args = ['EXPIRE', key, seconds.toString()];
-
+    parser.push('EXPIRE');
+    parser.pushKey(key);
+    parser.push(seconds.toString());
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    seconds: number,
+    mode?: 'NX' | 'XX' | 'GT' | 'LT'
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EXPIREAT.spec.ts b/packages/client/lib/commands/EXPIREAT.spec.ts
index 31efdcea398..1949fb051bb 100644
--- a/packages/client/lib/commands/EXPIREAT.spec.ts
+++ b/packages/client/lib/commands/EXPIREAT.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EXPIREAT from './EXPIREAT';
+import { parseArgs } from './generic-transformers';
 
 describe('EXPIREAT', () => {
   describe('transformArguments', () => {
     it('number', () => {
       assert.deepEqual(
-        EXPIREAT.transformArguments('key', 1),
+        parseArgs(EXPIREAT, 'key', 1),
         ['EXPIREAT', 'key', '1']
       );
     });
@@ -14,14 +15,14 @@ describe('EXPIREAT', () => {
     it('date', () => {
       const d = new Date();
       assert.deepEqual(
-        EXPIREAT.transformArguments('key', d),
+        parseArgs(EXPIREAT, 'key', d),
         ['EXPIREAT', 'key', Math.floor(d.getTime() / 1000).toString()]
       );
     });
 
     it('with set option', () => {
       assert.deepEqual(
-        EXPIREAT.transformArguments('key', 1, 'GT'),
+        parseArgs(EXPIREAT, 'key', 1, 'GT'),
         ['EXPIREAT', 'key', '1', 'GT']
       );
     });
diff --git a/packages/client/lib/commands/EXPIREAT.ts b/packages/client/lib/commands/EXPIREAT.ts
index 9a959a87f99..3a91c2d95d2 100644
--- a/packages/client/lib/commands/EXPIREAT.ts
+++ b/packages/client/lib/commands/EXPIREAT.ts
@@ -1,21 +1,27 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformEXAT } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     timestamp: number | Date,
     mode?: 'NX' | 'XX' | 'GT' | 'LT'
   ) {
-    const args = ['EXPIREAT', key, transformEXAT(timestamp)];
-
+    parser.push('EXPIREAT');
+    parser.pushKey(key);
+    parser.push(transformEXAT(timestamp));
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    timestamp: number | Date,
+    mode?: 'NX' | 'XX' | 'GT' | 'LT'
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/EXPIRETIME.spec.ts b/packages/client/lib/commands/EXPIRETIME.spec.ts
index 3c202d2427f..f2c8d3d4521 100644
--- a/packages/client/lib/commands/EXPIRETIME.spec.ts
+++ b/packages/client/lib/commands/EXPIRETIME.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EXPIRETIME from './EXPIRETIME';
+import { parseArgs } from './generic-transformers';
 
 describe('EXPIRETIME', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      EXPIRETIME.transformArguments('key'),
+      parseArgs(EXPIRETIME, 'key'),
       ['EXPIRETIME', 'key']
     );
   });
diff --git a/packages/client/lib/commands/EXPIRETIME.ts b/packages/client/lib/commands/EXPIRETIME.ts
index d6ac35aeb3d..6260d1ea41e 100644
--- a/packages/client/lib/commands/EXPIRETIME.ts
+++ b/packages/client/lib/commands/EXPIRETIME.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['EXPIRETIME', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('EXPIRETIME');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FAILOVER.spec.ts b/packages/client/lib/commands/FAILOVER.spec.ts
index 96602caff91..b23c3516f03 100644
--- a/packages/client/lib/commands/FAILOVER.spec.ts
+++ b/packages/client/lib/commands/FAILOVER.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import FAILOVER from './FAILOVER';
+import { parseArgs } from './generic-transformers';
 
 describe('FAILOVER', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FAILOVER.transformArguments(),
+        parseArgs(FAILOVER),
         ['FAILOVER']
       );
     });
@@ -13,7 +14,7 @@ describe('FAILOVER', () => {
     describe('with TO', () => {
       it('simple', () => {
         assert.deepEqual(
-          FAILOVER.transformArguments({
+          parseArgs(FAILOVER, {
             TO: {
               host: 'host',
               port: 6379
@@ -25,7 +26,7 @@ describe('FAILOVER', () => {
 
       it('with FORCE', () => {
         assert.deepEqual(
-          FAILOVER.transformArguments({
+          parseArgs(FAILOVER, {
             TO: {
               host: 'host',
               port: 6379,
@@ -39,7 +40,7 @@ describe('FAILOVER', () => {
 
     it('with ABORT', () => {
       assert.deepEqual(
-        FAILOVER.transformArguments({
+        parseArgs(FAILOVER, {
           ABORT: true
         }),
         ['FAILOVER', 'ABORT']
@@ -48,7 +49,7 @@ describe('FAILOVER', () => {
 
     it('with TIMEOUT', () => {
       assert.deepEqual(
-        FAILOVER.transformArguments({
+        parseArgs(FAILOVER, {
           TIMEOUT: 1
         }),
         ['FAILOVER', 'TIMEOUT', '1']
@@ -57,7 +58,7 @@ describe('FAILOVER', () => {
 
     it('with TO, ABORT, TIMEOUT', () => {
       assert.deepEqual(
-        FAILOVER.transformArguments({
+        parseArgs(FAILOVER, {
           TO: {
             host: 'host',
             port: 6379
diff --git a/packages/client/lib/commands/FAILOVER.ts b/packages/client/lib/commands/FAILOVER.ts
index 0c1e710d321..19621eaeca5 100644
--- a/packages/client/lib/commands/FAILOVER.ts
+++ b/packages/client/lib/commands/FAILOVER.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 interface FailoverOptions {
   TO?: {
@@ -11,26 +12,25 @@ interface FailoverOptions {
 }
 
 export default {
-  transformArguments(options?: FailoverOptions) {
-    const args = ['FAILOVER'];
+  parseCommand(parser: CommandParser, options?: FailoverOptions) {
+    parser.push('FAILOVER');
 
     if (options?.TO) {
-      args.push('TO', options.TO.host, options.TO.port.toString());
+      parser.pushVariadic(['TO', options.TO.host, options.TO.port.toString()]);
 
       if (options.TO.FORCE) {
-        args.push('FORCE');
+        parser.push('FORCE');
       }
     }
 
     if (options?.ABORT) {
-      args.push('ABORT');
+      parser.push('ABORT');
     }
 
     if (options?.TIMEOUT) {
-      args.push('TIMEOUT', options.TIMEOUT.toString());
+      parser.pushVariadic(['TIMEOUT', options.TIMEOUT.toString()]);
     }
-
-    return args;
   },
+  transformArguments(options?: FailoverOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FCALL.spec.ts b/packages/client/lib/commands/FCALL.spec.ts
index 286f2a371bf..6c3a65c1448 100644
--- a/packages/client/lib/commands/FCALL.spec.ts
+++ b/packages/client/lib/commands/FCALL.spec.ts
@@ -2,13 +2,14 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import { MATH_FUNCTION, loadMathFunction } from './FUNCTION_LOAD.spec';
 import FCALL from './FCALL';
+import { parseArgs } from './generic-transformers';
 
 describe('FCALL', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FCALL.transformArguments('function', {
+      parseArgs(FCALL, 'function', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/FCALL.ts b/packages/client/lib/commands/FCALL.ts
index ba371a81b13..52668d1d9dc 100644
--- a/packages/client/lib/commands/FCALL.ts
+++ b/packages/client/lib/commands/FCALL.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import EVAL, { transformEvalArguments } from './EVAL';
+import EVAL, { parseEvalArguments, transformEvalArguments } from './EVAL';
 
 export default {
   FIRST_KEY_INDEX: EVAL.FIRST_KEY_INDEX,
   IS_READ_ONLY: false,
+  parseCommand: parseEvalArguments.bind(undefined, 'FCALL'),
   transformArguments: transformEvalArguments.bind(undefined, 'FCALL'),
   transformReply: EVAL.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FCALL_RO.spec.ts b/packages/client/lib/commands/FCALL_RO.spec.ts
index 57edcebebef..447e00072be 100644
--- a/packages/client/lib/commands/FCALL_RO.spec.ts
+++ b/packages/client/lib/commands/FCALL_RO.spec.ts
@@ -2,13 +2,14 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import { MATH_FUNCTION, loadMathFunction } from './FUNCTION_LOAD.spec';
 import FCALL_RO from './FCALL_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('FCALL_RO', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FCALL_RO.transformArguments('function', {
+      parseArgs(FCALL_RO, 'function', {
         keys: ['key'],
         arguments: ['argument']
       }),
diff --git a/packages/client/lib/commands/FCALL_RO.ts b/packages/client/lib/commands/FCALL_RO.ts
index ec002a79f82..8ed0ad31f25 100644
--- a/packages/client/lib/commands/FCALL_RO.ts
+++ b/packages/client/lib/commands/FCALL_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import EVAL, { transformEvalArguments } from './EVAL';
+import EVAL, { parseEvalArguments, transformEvalArguments } from './EVAL';
 
 export default {
   FIRST_KEY_INDEX: EVAL.FIRST_KEY_INDEX,
   IS_READ_ONLY: false,
+  parseCommand: parseEvalArguments.bind(undefined, 'FCALL_RO'),
   transformArguments: transformEvalArguments.bind(undefined, 'FCALL_RO'),
   transformReply: EVAL.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FLUSHALL.spec.ts b/packages/client/lib/commands/FLUSHALL.spec.ts
index 63ad38dd7de..86daff1973a 100644
--- a/packages/client/lib/commands/FLUSHALL.spec.ts
+++ b/packages/client/lib/commands/FLUSHALL.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FLUSHALL, { REDIS_FLUSH_MODES } from './FLUSHALL';
+import { parseArgs } from './generic-transformers';
 
 describe('FLUSHALL', () => {
   describe('transformArguments', () => {
     it('default', () => {
       assert.deepEqual(
-        FLUSHALL.transformArguments(),
+        parseArgs(FLUSHALL),
         ['FLUSHALL']
       );
     });
 
     it('ASYNC', () => {
       assert.deepEqual(
-        FLUSHALL.transformArguments(REDIS_FLUSH_MODES.ASYNC),
+        parseArgs(FLUSHALL,REDIS_FLUSH_MODES.ASYNC),
         ['FLUSHALL', 'ASYNC']
       );
     });
 
     it('SYNC', () => {
       assert.deepEqual(
-        FLUSHALL.transformArguments(REDIS_FLUSH_MODES.SYNC),
+        parseArgs(FLUSHALL, REDIS_FLUSH_MODES.SYNC),
         ['FLUSHALL', 'SYNC']
       );
     });
diff --git a/packages/client/lib/commands/FLUSHALL.ts b/packages/client/lib/commands/FLUSHALL.ts
index 5e6484a991e..05f5a53d050 100644
--- a/packages/client/lib/commands/FLUSHALL.ts
+++ b/packages/client/lib/commands/FLUSHALL.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const REDIS_FLUSH_MODES = {
   ASYNC: 'ASYNC',
@@ -10,14 +11,12 @@ export type RedisFlushMode = typeof REDIS_FLUSH_MODES[keyof typeof REDIS_FLUSH_M
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(mode?: RedisFlushMode) {
-    const args = ['FLUSHALL'];
-    
+  parseCommand(parser: CommandParser, mode?: RedisFlushMode) {
+    parser.push('FLUSHALL');
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(mode?: RedisFlushMode) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FLUSHDB.spec.ts b/packages/client/lib/commands/FLUSHDB.spec.ts
index ad09ecfc945..795df637cb4 100644
--- a/packages/client/lib/commands/FLUSHDB.spec.ts
+++ b/packages/client/lib/commands/FLUSHDB.spec.ts
@@ -2,26 +2,27 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FLUSHDB from './FLUSHDB';
 import { REDIS_FLUSH_MODES } from './FLUSHALL';
+import { parseArgs } from './generic-transformers';
 
 describe('FLUSHDB', () => {
   describe('transformArguments', () => {
     it('default', () => {
       assert.deepEqual(
-        FLUSHDB.transformArguments(),
+        parseArgs(FLUSHDB),
         ['FLUSHDB']
       );
     });
 
     it('ASYNC', () => {
       assert.deepEqual(
-        FLUSHDB.transformArguments(REDIS_FLUSH_MODES.ASYNC),
+        parseArgs(FLUSHDB, REDIS_FLUSH_MODES.ASYNC),
         ['FLUSHDB', 'ASYNC']
       );
     });
 
     it('SYNC', () => {
       assert.deepEqual(
-        FLUSHDB.transformArguments(REDIS_FLUSH_MODES.SYNC),
+        parseArgs(FLUSHDB, REDIS_FLUSH_MODES.SYNC),
         ['FLUSHDB', 'SYNC']
       );
     });
diff --git a/packages/client/lib/commands/FLUSHDB.ts b/packages/client/lib/commands/FLUSHDB.ts
index 75c7a66f190..e5165281fe3 100644
--- a/packages/client/lib/commands/FLUSHDB.ts
+++ b/packages/client/lib/commands/FLUSHDB.ts
@@ -1,17 +1,16 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { RedisFlushMode } from './FLUSHALL';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(mode?: RedisFlushMode) {
-    const args = ['FLUSHDB'];
-    
+  parseCommand(parser: CommandParser, mode?: RedisFlushMode) {
+    parser.push('FLUSHDB');
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(mode?: RedisFlushMode) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_DELETE.spec.ts b/packages/client/lib/commands/FUNCTION_DELETE.spec.ts
index 1172e84b956..b33ea25916b 100644
--- a/packages/client/lib/commands/FUNCTION_DELETE.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_DELETE.spec.ts
@@ -2,13 +2,14 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_DELETE from './FUNCTION_DELETE';
 import { MATH_FUNCTION, loadMathFunction } from './FUNCTION_LOAD.spec';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION DELETE', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FUNCTION_DELETE.transformArguments('library'),
+      parseArgs(FUNCTION_DELETE, 'library'),
       ['FUNCTION', 'DELETE', 'library']
     );
   });
diff --git a/packages/client/lib/commands/FUNCTION_DELETE.ts b/packages/client/lib/commands/FUNCTION_DELETE.ts
index 1061cded17c..57b3c1e2472 100644
--- a/packages/client/lib/commands/FUNCTION_DELETE.ts
+++ b/packages/client/lib/commands/FUNCTION_DELETE.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(library: RedisArgument) {
-    return ['FUNCTION', 'DELETE', library];
+  parseCommand(parser: CommandParser, library: RedisArgument) {
+    parser.pushVariadic(['FUNCTION', 'DELETE', library]);
   },
+  transformArguments(library: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_DUMP.spec.ts b/packages/client/lib/commands/FUNCTION_DUMP.spec.ts
index 4d4e885e4f2..bbd6302bb6a 100644
--- a/packages/client/lib/commands/FUNCTION_DUMP.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_DUMP.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_DUMP from './FUNCTION_DUMP';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION DUMP', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FUNCTION_DUMP.transformArguments(),
+      parseArgs(FUNCTION_DUMP),
       ['FUNCTION', 'DUMP']
     );
   });
diff --git a/packages/client/lib/commands/FUNCTION_DUMP.ts b/packages/client/lib/commands/FUNCTION_DUMP.ts
index 8f6ff047fa7..39e83381477 100644
--- a/packages/client/lib/commands/FUNCTION_DUMP.ts
+++ b/packages/client/lib/commands/FUNCTION_DUMP.ts
@@ -1,10 +1,12 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['FUNCTION', 'DUMP'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['FUNCTION', 'DUMP'])
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_FLUSH.spec.ts b/packages/client/lib/commands/FUNCTION_FLUSH.spec.ts
index 5601784ed6a..4fe90bdb607 100644
--- a/packages/client/lib/commands/FUNCTION_FLUSH.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_FLUSH.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_FLUSH from './FUNCTION_FLUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION FLUSH', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('FUNCTION FLUSH', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FUNCTION_FLUSH.transformArguments(),
+        parseArgs(FUNCTION_FLUSH),
         ['FUNCTION', 'FLUSH']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        FUNCTION_FLUSH.transformArguments('SYNC'),
+        parseArgs(FUNCTION_FLUSH, 'SYNC'),
         ['FUNCTION', 'FLUSH', 'SYNC']
       );
     });
diff --git a/packages/client/lib/commands/FUNCTION_FLUSH.ts b/packages/client/lib/commands/FUNCTION_FLUSH.ts
index 844d3586d90..ada0e7b42fd 100644
--- a/packages/client/lib/commands/FUNCTION_FLUSH.ts
+++ b/packages/client/lib/commands/FUNCTION_FLUSH.ts
@@ -1,17 +1,17 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { RedisFlushMode } from './FLUSHALL';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(mode?: RedisFlushMode) {
-    const args = ['FUNCTION', 'FLUSH'];
-    
+  parseCommand(parser: CommandParser, mode?: RedisFlushMode) {
+    parser.pushVariadic(['FUNCTION', 'FLUSH']);
+
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(mode?: RedisFlushMode) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_KILL.spec.ts b/packages/client/lib/commands/FUNCTION_KILL.spec.ts
index be231e41180..c4dbd124d30 100644
--- a/packages/client/lib/commands/FUNCTION_KILL.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_KILL.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils from '../test-utils';
 import FUNCTION_KILL from './FUNCTION_KILL';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION KILL', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FUNCTION_KILL.transformArguments(),
+      parseArgs(FUNCTION_KILL),
       ['FUNCTION', 'KILL']
     );
   });
diff --git a/packages/client/lib/commands/FUNCTION_KILL.ts b/packages/client/lib/commands/FUNCTION_KILL.ts
index f452b0b80d9..20ce295554a 100644
--- a/packages/client/lib/commands/FUNCTION_KILL.ts
+++ b/packages/client/lib/commands/FUNCTION_KILL.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['FUNCTION', 'KILL'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['FUNCTION', 'KILL']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_LIST.spec.ts b/packages/client/lib/commands/FUNCTION_LIST.spec.ts
index e269d3150b6..6d9b28acf90 100644
--- a/packages/client/lib/commands/FUNCTION_LIST.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_LIST.spec.ts
@@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_LIST from './FUNCTION_LIST';
 import { MATH_FUNCTION, loadMathFunction } from './FUNCTION_LOAD.spec';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION LIST', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -9,14 +10,14 @@ describe('FUNCTION LIST', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FUNCTION_LIST.transformArguments(),
+        parseArgs(FUNCTION_LIST),
         ['FUNCTION', 'LIST']
       );
     });
 
     it('with LIBRARYNAME', () => {
       assert.deepEqual(
-        FUNCTION_LIST.transformArguments({
+        parseArgs(FUNCTION_LIST, {
           LIBRARYNAME: 'patter*'
         }),
         ['FUNCTION', 'LIST', 'LIBRARYNAME', 'patter*']
diff --git a/packages/client/lib/commands/FUNCTION_LIST.ts b/packages/client/lib/commands/FUNCTION_LIST.ts
index 07c1ff2a000..54130e2043c 100644
--- a/packages/client/lib/commands/FUNCTION_LIST.ts
+++ b/packages/client/lib/commands/FUNCTION_LIST.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesToMapReply, BlobStringReply, ArrayReply, NullReply, SetReply, UnwrapReply, Resp2Reply, CommandArguments, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface FunctionListOptions {
   LIBRARYNAME?: RedisArgument;
@@ -19,6 +20,13 @@ export type FunctionListReply = ArrayReply<TuplesToMapReply<FunctionListReplyIte
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
+  parseCommand(parser: CommandParser, options?: FunctionListOptions) {
+    parser.pushVariadic(['FUNCTION', 'LIST']);
+
+    if (options?.LIBRARYNAME) {
+      parser.pushVariadic(['LIBRARYNAME', options.LIBRARYNAME]);
+    }
+  },
   transformArguments(options?: FunctionListOptions) {
     const args: CommandArguments = ['FUNCTION', 'LIST'];
 
diff --git a/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.spec.ts b/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.spec.ts
index 8ff40582460..f44db9ba037 100644
--- a/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.spec.ts
@@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_LIST_WITHCODE from './FUNCTION_LIST_WITHCODE';
 import { MATH_FUNCTION, loadMathFunction } from './FUNCTION_LOAD.spec';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION LIST WITHCODE', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -9,14 +10,14 @@ describe('FUNCTION LIST WITHCODE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FUNCTION_LIST_WITHCODE.transformArguments(),
+        parseArgs(FUNCTION_LIST_WITHCODE),
         ['FUNCTION', 'LIST', 'WITHCODE']
       );
     });
 
     it('with LIBRARYNAME', () => {
       assert.deepEqual(
-        FUNCTION_LIST_WITHCODE.transformArguments({
+        parseArgs(FUNCTION_LIST_WITHCODE, {
           LIBRARYNAME: 'patter*'
         }),
         ['FUNCTION', 'LIST', 'LIBRARYNAME', 'patter*', 'WITHCODE']
diff --git a/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.ts b/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.ts
index 47a02a3da8a..0d20c88b797 100644
--- a/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.ts
+++ b/packages/client/lib/commands/FUNCTION_LIST_WITHCODE.ts
@@ -1,4 +1,5 @@
 import { TuplesToMapReply, BlobStringReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import FUNCTION_LIST, { FunctionListReplyItem } from './FUNCTION_LIST';
 
 export type FunctionListWithCodeReply = ArrayReply<TuplesToMapReply<[
@@ -9,11 +10,11 @@ export type FunctionListWithCodeReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: FUNCTION_LIST.FIRST_KEY_INDEX,
   IS_READ_ONLY: FUNCTION_LIST.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof FUNCTION_LIST.transformArguments>) {
-    const redisArgs = FUNCTION_LIST.transformArguments(...args);
-    redisArgs.push('WITHCODE');
-    return redisArgs;
+  parseCommand(parser: CommandParser, ...args: Parameters<typeof FUNCTION_LIST.transformArguments>) {
+    FUNCTION_LIST.parseCommand(parser, ...args);
+    parser.push('WITHCODE');
   },
+  transformArguments(...args: Parameters<typeof FUNCTION_LIST.transformArguments>) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<FunctionListWithCodeReply>>) => {
       return reply.map(library => {
diff --git a/packages/client/lib/commands/FUNCTION_LOAD.spec.ts b/packages/client/lib/commands/FUNCTION_LOAD.spec.ts
index fe896bdf8c8..ca6f7ef643f 100644
--- a/packages/client/lib/commands/FUNCTION_LOAD.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_LOAD.spec.ts
@@ -3,6 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_LOAD from './FUNCTION_LOAD';
 import { RedisClientType } from '../client';
 import { NumberReply, RedisFunctions, RedisModules, RedisScripts, RespVersions } from '../RESP/types';
+import { parseArgs } from './generic-transformers';
 
 
 
@@ -53,14 +54,14 @@ describe('FUNCTION LOAD', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FUNCTION_LOAD.transformArguments('code'),
+        parseArgs(FUNCTION_LOAD, 'code'),
         ['FUNCTION', 'LOAD', 'code']
       );
     });
 
     it('with REPLACE', () => {
       assert.deepEqual(
-        FUNCTION_LOAD.transformArguments('code', {
+        parseArgs(FUNCTION_LOAD, 'code', {
           REPLACE: true
         }),
         ['FUNCTION', 'LOAD', 'REPLACE', 'code']
diff --git a/packages/client/lib/commands/FUNCTION_LOAD.ts b/packages/client/lib/commands/FUNCTION_LOAD.ts
index 32b030909ad..fdea6ccb7f6 100644
--- a/packages/client/lib/commands/FUNCTION_LOAD.ts
+++ b/packages/client/lib/commands/FUNCTION_LOAD.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, CommandArguments, BlobStringReply, Command } from '../RESP/types';
+import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface FunctionLoadOptions {
   REPLACE?: boolean;
@@ -7,16 +8,15 @@ export interface FunctionLoadOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(code: RedisArgument, options?: FunctionLoadOptions) {
-    const args: CommandArguments = ['FUNCTION', 'LOAD'];
+  parseCommand(parser: CommandParser, code: RedisArgument, options?: FunctionLoadOptions) {
+    parser.pushVariadic(['FUNCTION', 'LOAD']);
 
     if (options?.REPLACE) {
-      args.push('REPLACE');
+      parser.push('REPLACE');
     }
 
-    args.push(code);
-
-    return args;
+    parser.push(code);
   },
+  transformArguments(code: RedisArgument, options?: FunctionLoadOptions) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_RESTORE.spec.ts b/packages/client/lib/commands/FUNCTION_RESTORE.spec.ts
index 465e99b6104..72d7d1d6204 100644
--- a/packages/client/lib/commands/FUNCTION_RESTORE.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_RESTORE.spec.ts
@@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_RESTORE from './FUNCTION_RESTORE';
 import { RESP_TYPES } from '../RESP/decoder';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION RESTORE', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -9,14 +10,14 @@ describe('FUNCTION RESTORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        FUNCTION_RESTORE.transformArguments('dump'),
+        parseArgs(FUNCTION_RESTORE, 'dump'),
         ['FUNCTION', 'RESTORE', 'dump']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        FUNCTION_RESTORE.transformArguments('dump', {
+        parseArgs(FUNCTION_RESTORE, 'dump', {
           mode: 'APPEND'
         }),
         ['FUNCTION', 'RESTORE', 'dump', 'APPEND']
diff --git a/packages/client/lib/commands/FUNCTION_RESTORE.ts b/packages/client/lib/commands/FUNCTION_RESTORE.ts
index 8c875530562..c89cff2ad42 100644
--- a/packages/client/lib/commands/FUNCTION_RESTORE.ts
+++ b/packages/client/lib/commands/FUNCTION_RESTORE.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface FunctionRestoreOptions {
   mode?: 'FLUSH' | 'APPEND' | 'REPLACE';
@@ -7,14 +8,13 @@ export interface FunctionRestoreOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(dump: RedisArgument, options?: FunctionRestoreOptions) {
-    const args = ['FUNCTION', 'RESTORE', dump];
+  parseCommand(parser: CommandParser, dump: RedisArgument, options?: FunctionRestoreOptions) {
+    parser.pushVariadic(['FUNCTION', 'RESTORE', dump]);
 
     if (options?.mode) {
-      args.push(options.mode);
+      parser.push(options.mode);
     }
-
-    return args;
   },
+  transformArguments(dump: RedisArgument, options?: FunctionRestoreOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/FUNCTION_STATS.spec.ts b/packages/client/lib/commands/FUNCTION_STATS.spec.ts
index b48b012614f..a3c5e00fe72 100644
--- a/packages/client/lib/commands/FUNCTION_STATS.spec.ts
+++ b/packages/client/lib/commands/FUNCTION_STATS.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FUNCTION_STATS from './FUNCTION_STATS';
+import { parseArgs } from './generic-transformers';
 
 describe('FUNCTION STATS', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      FUNCTION_STATS.transformArguments(),
+      parseArgs(FUNCTION_STATS),
       ['FUNCTION', 'STATS']
     );
   });
diff --git a/packages/client/lib/commands/FUNCTION_STATS.ts b/packages/client/lib/commands/FUNCTION_STATS.ts
index 138d1fb82d5..7506942f4d9 100644
--- a/packages/client/lib/commands/FUNCTION_STATS.ts
+++ b/packages/client/lib/commands/FUNCTION_STATS.ts
@@ -1,4 +1,5 @@
 import { Command, TuplesToMapReply, BlobStringReply, NullReply, NumberReply, MapReply, Resp2Reply, UnwrapReply } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { isNullReply } from './generic-transformers';
 
 type RunningScript = NullReply | TuplesToMapReply<[
@@ -22,9 +23,10 @@ type FunctionStatsReply = TuplesToMapReply<[
 export default {
   IS_READ_ONLY: true,
   FIRST_KEY_INDEX: undefined,
-  transformArguments() {
-    return ['FUNCTION', 'STATS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['FUNCTION', 'STATS']);
   },
+  transformArguments() { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<FunctionStatsReply>>) => {
       return {
diff --git a/packages/client/lib/commands/GEOADD.spec.ts b/packages/client/lib/commands/GEOADD.spec.ts
index 14195ed289c..d947141a318 100644
--- a/packages/client/lib/commands/GEOADD.spec.ts
+++ b/packages/client/lib/commands/GEOADD.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOADD from './GEOADD';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOADD', () => {
   describe('transformArguments', () => {
     it('one member', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', {
+        parseArgs(GEOADD, 'key', {
           member: 'member',
           longitude: 1,
           latitude: 2
@@ -17,7 +18,7 @@ describe('GEOADD', () => {
 
     it('multiple members', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', [{
+        parseArgs(GEOADD, 'key', [{
           longitude: 1,
           latitude: 2,
           member: '3',
@@ -32,7 +33,7 @@ describe('GEOADD', () => {
 
     it('with condition', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', {
+        parseArgs(GEOADD, 'key', {
           longitude: 1,
           latitude: 2,
           member: 'member'
@@ -45,7 +46,7 @@ describe('GEOADD', () => {
 
     it('with NX (backwards compatibility)', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', {
+        parseArgs(GEOADD, 'key', {
           longitude: 1,
           latitude: 2,
           member: 'member'
@@ -58,7 +59,7 @@ describe('GEOADD', () => {
 
     it('with CH', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', {
+        parseArgs(GEOADD, 'key', {
           longitude: 1,
           latitude: 2,
           member: 'member'
@@ -71,7 +72,7 @@ describe('GEOADD', () => {
 
     it('with condition, CH', () => {
       assert.deepEqual(
-        GEOADD.transformArguments('key', {
+        parseArgs(GEOADD, 'key', {
           longitude: 1,
           latitude: 2,
           member: 'member'
diff --git a/packages/client/lib/commands/GEOADD.ts b/packages/client/lib/commands/GEOADD.ts
index f89f6b80e82..2f3517c147f 100644
--- a/packages/client/lib/commands/GEOADD.ts
+++ b/packages/client/lib/commands/GEOADD.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, CommandArguments, NumberReply, Command } from '../RESP/types';
+import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { GeoCoordinates } from './GEOSEARCH';
 
 export interface GeoMember extends GeoCoordinates {
@@ -21,45 +22,53 @@ export interface GeoAddOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     toAdd: GeoMember | Array<GeoMember>,
     options?: GeoAddOptions
   ) {
-    const args = ['GEOADD', key];
+    parser.push('GEOADD')
+    parser.pushKey(key);
 
     if (options?.condition) {
-      args.push(options.condition);
+      parser.push(options.condition);
     } else if (options?.NX) {
-      args.push('NX');
+      parser.push('NX');
     } else if (options?.XX) {
-      args.push('XX');
+      parser.push('XX');
     }
 
     if (options?.CH) {
-      args.push('CH');
+      parser.push('CH');
     }
 
     if (Array.isArray(toAdd)) {
       for (const member of toAdd) {
-        pushMember(args, member);
+        pushMember(parser, member);
       }
     } else {
-      pushMember(args, toAdd);
+      pushMember(parser, toAdd);
     }
 
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    toAdd: GeoMember | Array<GeoMember>,
+    options?: GeoAddOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
 
 function pushMember(
-  args: CommandArguments,
+  parser: CommandParser,
   { longitude, latitude, member }: GeoMember
 ) {
-  args.push(
-    longitude.toString(),
-    latitude.toString(),
-    member
+  parser.pushVariadic(
+    [
+      longitude.toString(),
+      latitude.toString(),
+      member
+    ]
   );
 }
diff --git a/packages/client/lib/commands/GEODIST.spec.ts b/packages/client/lib/commands/GEODIST.spec.ts
index eb5a1ef801e..a23df405d1d 100644
--- a/packages/client/lib/commands/GEODIST.spec.ts
+++ b/packages/client/lib/commands/GEODIST.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEODIST from './GEODIST';
+import { parseArgs } from './generic-transformers';
 
 describe('GEODIST', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        GEODIST.transformArguments('key', '1', '2'),
+        parseArgs(GEODIST, 'key', '1', '2'),
         ['GEODIST', 'key', '1', '2']
       );
     });
 
     it('with unit', () => {
       assert.deepEqual(
-        GEODIST.transformArguments('key', '1', '2', 'm'),
+        parseArgs(GEODIST, 'key', '1', '2', 'm'),
         ['GEODIST', 'key', '1', '2', 'm']
       );
     });
diff --git a/packages/client/lib/commands/GEODIST.ts b/packages/client/lib/commands/GEODIST.ts
index 3e684d67579..4fc453cfe5f 100644
--- a/packages/client/lib/commands/GEODIST.ts
+++ b/packages/client/lib/commands/GEODIST.ts
@@ -1,23 +1,31 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { GeoUnits } from './GEOSEARCH';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(parser: CommandParser,
     key: RedisArgument,
     member1: RedisArgument,
     member2: RedisArgument,
     unit?: GeoUnits
   ) {
-    const args = ['GEODIST', key, member1, member2];
+    parser.setCachable();
+    parser.push('GEODIST');
+    parser.pushKey(key);
+    parser.pushVariadic([member1, member2]);
 
     if (unit) {
-      args.push(unit);
+      parser.push(unit);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    member1: RedisArgument,
+    member2: RedisArgument,
+    unit?: GeoUnits
+  ) { return [] },
   transformReply(reply: BlobStringReply | NullReply) {
     return reply === null ? null : Number(reply);
   }
diff --git a/packages/client/lib/commands/GEOHASH.spec.ts b/packages/client/lib/commands/GEOHASH.spec.ts
index 8efe55d89b6..ad26dff8434 100644
--- a/packages/client/lib/commands/GEOHASH.spec.ts
+++ b/packages/client/lib/commands/GEOHASH.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOHASH from './GEOHASH';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOHASH', () => {
   describe('transformArguments', () => {
     it('single member', () => {
       assert.deepEqual(
-        GEOHASH.transformArguments('key', 'member'),
+        parseArgs(GEOHASH, 'key', 'member'),
         ['GEOHASH', 'key', 'member']
       );
     });
 
     it('multiple members', () => {
       assert.deepEqual(
-        GEOHASH.transformArguments('key', ['1', '2']),
+        parseArgs(GEOHASH, 'key', ['1', '2']),
         ['GEOHASH', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/GEOHASH.ts b/packages/client/lib/commands/GEOHASH.ts
index d8d2732e512..07bce26a5bf 100644
--- a/packages/client/lib/commands/GEOHASH.ts
+++ b/packages/client/lib/commands/GEOHASH.ts
@@ -1,14 +1,16 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    member: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['GEOHASH', key], member);
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('GEOHASH');
+    parser.pushKey(key);
+    parser.pushVariadic(member);
   },
+  transformArguments(key: RedisArgument, member: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEOPOS.spec.ts b/packages/client/lib/commands/GEOPOS.spec.ts
index 20ad5c5c942..247dd91d222 100644
--- a/packages/client/lib/commands/GEOPOS.spec.ts
+++ b/packages/client/lib/commands/GEOPOS.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOPOS from './GEOPOS';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOPOS', () => {
   describe('transformArguments', () => {
     it('single member', () => {
       assert.deepEqual(
-        GEOPOS.transformArguments('key', 'member'),
+        parseArgs(GEOPOS, 'key', 'member'),
         ['GEOPOS', 'key', 'member']
       );
     });
 
     it('multiple members', () => {
       assert.deepEqual(
-        GEOPOS.transformArguments('key', ['1', '2']),
+        parseArgs(GEOPOS, 'key', ['1', '2']),
         ['GEOPOS', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/GEOPOS.ts b/packages/client/lib/commands/GEOPOS.ts
index 30273c64c18..f888cbc8198 100644
--- a/packages/client/lib/commands/GEOPOS.ts
+++ b/packages/client/lib/commands/GEOPOS.ts
@@ -1,15 +1,17 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, NullReply, UnwrapReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    member: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['GEOPOS', key], member);
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('GEOPOS');
+    parser.pushKey(key);
+    parser.pushVariadic(member);
   },
+  transformArguments(key: RedisArgument, member: RedisVariadicArgument) { return [] },
   transformReply(reply: UnwrapReply<ArrayReply<TuplesReply<[BlobStringReply, BlobStringReply]> | NullReply>>) {
     return reply.map(item => {
       const unwrapped = item as unknown as UnwrapReply<typeof item>;
diff --git a/packages/client/lib/commands/GEORADIUS.spec.ts b/packages/client/lib/commands/GEORADIUS.spec.ts
index 533e48f6898..3c33395c5f6 100644
--- a/packages/client/lib/commands/GEORADIUS.spec.ts
+++ b/packages/client/lib/commands/GEORADIUS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUS from './GEORADIUS';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      GEORADIUS.transformArguments('key', {
+      parseArgs(GEORADIUS, 'key', {
         longitude: 1,
         latitude: 2
       }, 3, 'm'),
diff --git a/packages/client/lib/commands/GEORADIUS.ts b/packages/client/lib/commands/GEORADIUS.ts
index e777432f090..6f74b0b435b 100644
--- a/packages/client/lib/commands/GEORADIUS.ts
+++ b/packages/client/lib/commands/GEORADIUS.ts
@@ -1,31 +1,41 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { GeoCoordinates, GeoUnits, GeoSearchOptions, pushGeoSearchOptions } from './GEOSEARCH';
+import { CommandParser } from '../client/parser';
+import { GeoCoordinates, GeoUnits, GeoSearchOptions, parseGeoSearchOptions } from './GEOSEARCH';
 
-export function transformGeoRadiusArguments(
+export function parseGeoRadiusArguments(
   command: RedisArgument,
+  cachable: boolean,
+  parser: CommandParser,
   key: RedisArgument,
   from: GeoCoordinates,
   radius: number,
   unit: GeoUnits,
   options?: GeoSearchOptions
 ) {
-  const args = [
-    command,
-    key,
-    from.longitude.toString(),
-    from.latitude.toString(),
-    radius.toString(),
-    unit
-  ];
+  if (cachable) {
+    parser.setCachable();
+  }
 
-  pushGeoSearchOptions(args, options);
+  parser.push(command);
+  parser.pushKey(key);
+  parser.pushVariadic([from.longitude.toString(), from.latitude.toString(), radius.toString(), unit]);
 
-  return args;
+  parseGeoSearchOptions(parser, options)
 }
 
+export function transformGeoRadiusArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  from: GeoCoordinates,
+  radius: number,
+  unit: GeoUnits,
+  options?: GeoSearchOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
+  parseCommand: parseGeoRadiusArguments.bind(undefined, 'GEORADIUS', false),
   transformArguments: transformGeoRadiusArguments.bind(undefined, 'GEORADIUS'),
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER.spec.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER.spec.ts
index 57349a79acb..c81c3d75815 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER.spec.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUSBYMEMBER from './GEORADIUSBYMEMBER';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUSBYMEMBER', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      GEORADIUSBYMEMBER.transformArguments('key', 'member', 3, 'm'),
+      parseArgs(GEORADIUSBYMEMBER, 'key', 'member', 3, 'm'),
       ['GEORADIUSBYMEMBER', 'key', 'member', '3', 'm']
     );
   });
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER.ts
index 13b52a30630..cf0982b725e 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER.ts
@@ -1,30 +1,41 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { GeoUnits, GeoSearchOptions, pushGeoSearchOptions } from './GEOSEARCH';
+import { CommandParser } from '../client/parser';
+import { GeoUnits, GeoSearchOptions, parseGeoSearchOptions } from './GEOSEARCH';
 
-export function transformGeoRadiusByMemberArguments(
+export function parseGeoRadiusByMemberArguments(
   command: RedisArgument,
+  cachable: boolean,
+  parser: CommandParser,
   key: RedisArgument,
   from: RedisArgument,
   radius: number,
   unit: GeoUnits,
   options?: GeoSearchOptions
 ) {
-  const args = [
-    command,
-    key,
-    from,
-    radius.toString(),
-    unit
-  ];
+  if (cachable) {
+    parser.setCachable();
+  }
 
-  pushGeoSearchOptions(args, options);
+  parser.push(command);
+  parser.pushKey(key);
+  parser.pushVariadic([from, radius.toString(), unit]);
 
-  return args;
+  parseGeoSearchOptions(parser, options);
 }
 
+export function transformGeoRadiusByMemberArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  from: RedisArgument,
+  radius: number,
+  unit: GeoUnits,
+  options?: GeoSearchOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
+  parseCommand: parseGeoRadiusByMemberArguments.bind(undefined, 'GEORADIUSBYMEMBER', false),
   transformArguments: transformGeoRadiusByMemberArguments.bind(undefined, 'GEORADIUSBYMEMBER'),
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.spec.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.spec.ts
index abf10013973..bd4aa86dec1 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.spec.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUSBYMEMBER_RO from './GEORADIUSBYMEMBER_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUSBYMEMBER_RO', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      GEORADIUSBYMEMBER_RO.transformArguments('key', 'member', 3, 'm'),
+      parseArgs(GEORADIUSBYMEMBER_RO, 'key', 'member', 3, 'm'),
       ['GEORADIUSBYMEMBER_RO', 'key', 'member', '3', 'm']
     );
   });
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.ts
index 7f85ed15df7..3f6c9838bcd 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import GEORADIUSBYMEMBER, { transformGeoRadiusByMemberArguments } from './GEORADIUSBYMEMBER';
+import GEORADIUSBYMEMBER, { parseGeoRadiusByMemberArguments, transformGeoRadiusByMemberArguments } from './GEORADIUSBYMEMBER';
 
 export default {
   FIRST_KEY_INDEX: GEORADIUSBYMEMBER.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseGeoRadiusByMemberArguments.bind(undefined, 'GEORADIUSBYMEMBER_RO', true),
   transformArguments: transformGeoRadiusByMemberArguments.bind(undefined, 'GEORADIUSBYMEMBER_RO'),
   transformReply: GEORADIUSBYMEMBER.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.spec.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.spec.ts
index bcf91266365..52b31b03594 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.spec.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.spec.ts
@@ -3,6 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUSBYMEMBER_RO_WITH from './GEORADIUSBYMEMBER_RO_WITH';
 import { CommandArguments } from '../RESP/types';
 import { GEO_REPLY_WITH } from './GEOSEARCH_WITH';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUSBYMEMBER_RO WITH', () => {
   it('transformArguments', () => {
@@ -10,7 +11,7 @@ describe('GEORADIUSBYMEMBER_RO WITH', () => {
     expectedReply.preserve = ['WITHDIST'];
 
     assert.deepEqual(
-      GEORADIUSBYMEMBER_RO_WITH.transformArguments('key', 'member', 3, 'm', [
+      parseArgs(GEORADIUSBYMEMBER_RO_WITH, 'key', 'member', 3, 'm', [
         GEO_REPLY_WITH.DISTANCE
       ]),
       expectedReply
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.ts
index 5fb945a1f9c..2e7cd326780 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_RO_WITH.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import GEORADIUSBYMEMBER_WITH, { transformGeoRadiusByMemberWithArguments } from './GEORADIUSBYMEMBER_WITH';
+import GEORADIUSBYMEMBER_WITH, { parseGeoRadiusByMemberWithArguments, transformGeoRadiusByMemberWithArguments } from './GEORADIUSBYMEMBER_WITH';
 
 export default {
   FIRST_KEY_INDEX: GEORADIUSBYMEMBER_WITH.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseGeoRadiusByMemberWithArguments.bind(undefined, 'GEORADIUSBYMEMBER_RO', true),
   transformArguments: transformGeoRadiusByMemberWithArguments.bind(undefined, 'GEORADIUSBYMEMBER_RO'),
   transformReply: GEORADIUSBYMEMBER_WITH.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.spec.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.spec.ts
index 3d44060f205..9edb08d1eae 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.spec.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUSBYMEMBER_STORE from './GEORADIUSBYMEMBER_STORE';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUSBYMEMBER STORE', () => {
   describe('transformArguments', () => {
     it('STORE', () => {
       assert.deepEqual(
-        GEORADIUSBYMEMBER_STORE.transformArguments('key', 'member', 3, 'm', 'destination'),
+        parseArgs(GEORADIUSBYMEMBER_STORE, 'key', 'member', 3, 'm', 'destination'),
         ['GEORADIUSBYMEMBER', 'key', 'member', '3', 'm', 'STORE', 'destination']
       );
     });
 
     it('STOREDIST', () => {
       assert.deepEqual(
-        GEORADIUSBYMEMBER_STORE.transformArguments('key', 'member', 3, 'm', 'destination', {
+        parseArgs(GEORADIUSBYMEMBER_STORE, 'key', 'member', 3, 'm', 'destination', {
           STOREDIST: true
         }),
         ['GEORADIUSBYMEMBER', 'key', 'member', '3', 'm', 'STOREDIST', 'destination']
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.ts
index 90419963110..4617deda96d 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_STORE.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import GEORADIUSBYMEMBER, { transformGeoRadiusByMemberArguments } from './GEORADIUSBYMEMBER';
+import { CommandParser } from '../client/parser';
+import GEORADIUSBYMEMBER, { parseGeoRadiusByMemberArguments } from './GEORADIUSBYMEMBER';
 import { GeoSearchOptions, GeoUnits } from './GEOSEARCH';
 
 export interface GeoRadiusStoreOptions extends GeoSearchOptions {
@@ -9,7 +10,8 @@ export interface GeoRadiusStoreOptions extends GeoSearchOptions {
 export default {
   FIRST_KEY_INDEX: GEORADIUSBYMEMBER.FIRST_KEY_INDEX,
   IS_READ_ONLY: GEORADIUSBYMEMBER.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     from: RedisArgument,
     radius: number,
@@ -17,15 +19,21 @@ export default {
     destination: RedisArgument,
     options?: GeoRadiusStoreOptions
   ) {
-    const args = transformGeoRadiusByMemberArguments('GEORADIUSBYMEMBER', key, from, radius, unit, options);
+    parseGeoRadiusByMemberArguments('GEORADIUSBYMEMBER', false, parser, key, from, radius, unit, options);
 
     if (options?.STOREDIST) {
-      args.push('STOREDIST', destination);
+      parser.pushVariadic(['STOREDIST', destination]);
     } else {
-      args.push('STORE', destination);
+      parser.pushVariadic(['STORE', destination]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    from: RedisArgument,
+    radius: number,
+    unit: GeoUnits,
+    destination: RedisArgument,
+    options?: GeoRadiusStoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.spec.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.spec.ts
index ffe3b2efff3..9d634d60656 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.spec.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.spec.ts
@@ -3,6 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUSBYMEMBER_WITH from './GEORADIUSBYMEMBER_WITH';
 import { CommandArguments } from '../RESP/types';
 import { GEO_REPLY_WITH } from './GEOSEARCH_WITH';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUSBYMEMBER WITH', () => {
   it('transformArguments', () => {
@@ -10,7 +11,7 @@ describe('GEORADIUSBYMEMBER WITH', () => {
     expectedReply.preserve = ['WITHDIST'];
 
     assert.deepEqual(
-      GEORADIUSBYMEMBER_WITH.transformArguments('key', 'member', 3, 'm', [
+      parseArgs(GEORADIUSBYMEMBER_WITH, 'key', 'member', 3, 'm', [
         GEO_REPLY_WITH.DISTANCE
       ]),
       expectedReply
diff --git a/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.ts b/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.ts
index be9472a438f..eb195189b49 100644
--- a/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.ts
+++ b/packages/client/lib/commands/GEORADIUSBYMEMBER_WITH.ts
@@ -1,10 +1,13 @@
-import { RedisArgument, CommandArguments, Command } from '../RESP/types';
+import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import GEORADIUSBYMEMBER from './GEORADIUSBYMEMBER';
-import { GeoSearchOptions, GeoUnits, pushGeoSearchOptions } from './GEOSEARCH';
+import { GeoSearchOptions, GeoUnits, parseGeoSearchOptions } from './GEOSEARCH';
 import GEOSEARCH_WITH, { GeoReplyWith } from './GEOSEARCH_WITH';
 
-export function transformGeoRadiusByMemberWithArguments(
+export function parseGeoRadiusByMemberWithArguments(
   command: RedisArgument,
+  cachable: boolean,
+  parser: CommandParser,
   key: RedisArgument,
   from: RedisArgument,
   radius: number,
@@ -12,25 +15,33 @@ export function transformGeoRadiusByMemberWithArguments(
   replyWith: Array<GeoReplyWith>,
   options?: GeoSearchOptions
 ) {
-  const args: CommandArguments = [
-    command,
-    key,
-    from,
-    radius.toString(),
-    unit
-  ];
-
-  pushGeoSearchOptions(args, options);
+  if (cachable) {
+    parser.setCachable();
+  }
 
-  args.push(...replyWith);
-  args.preserve = replyWith;
+  parser.push(command);
+  parser.pushKey(key);
+  parser.pushVariadic([from, radius.toString(), unit]);
+  parseGeoSearchOptions(parser, options);
 
-  return args;
+  parser.pushVariadic(replyWith);
+  parser.setPreserve(replyWith);
 }
 
+export function transformGeoRadiusByMemberWithArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  from: RedisArgument,
+  radius: number,
+  unit: GeoUnits,
+  replyWith: Array<GeoReplyWith>,
+  options?: GeoSearchOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: GEORADIUSBYMEMBER.FIRST_KEY_INDEX,
   IS_READ_ONLY: GEORADIUSBYMEMBER.IS_READ_ONLY,
+  parseCommand: parseGeoRadiusByMemberWithArguments.bind(undefined, 'GEORADIUSBYMEMBER', false),
   transformArguments: transformGeoRadiusByMemberWithArguments.bind(undefined, 'GEORADIUSBYMEMBER'),
   transformReply: GEOSEARCH_WITH.transformReply
 } as const satisfies Command;
\ No newline at end of file
diff --git a/packages/client/lib/commands/GEORADIUS_RO.spec.ts b/packages/client/lib/commands/GEORADIUS_RO.spec.ts
index 43a2ef1d583..917eba3ab8e 100644
--- a/packages/client/lib/commands/GEORADIUS_RO.spec.ts
+++ b/packages/client/lib/commands/GEORADIUS_RO.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUS_RO from './GEORADIUS_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUS_RO', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      GEORADIUS_RO.transformArguments('key', {
+      parseArgs(GEORADIUS_RO, 'key', {
         longitude: 1,
         latitude: 2
       }, 3, 'm'),
diff --git a/packages/client/lib/commands/GEORADIUS_RO.ts b/packages/client/lib/commands/GEORADIUS_RO.ts
index be8bb4b530d..d5233efd50f 100644
--- a/packages/client/lib/commands/GEORADIUS_RO.ts
+++ b/packages/client/lib/commands/GEORADIUS_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import GEORADIUS, { transformGeoRadiusArguments } from './GEORADIUS';
+import GEORADIUS, { parseGeoRadiusArguments, transformGeoRadiusArguments } from './GEORADIUS';
 
 export default {
   FIRST_KEY_INDEX: GEORADIUS.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseGeoRadiusArguments.bind(undefined, 'GEORADIUS_RO', true),
   transformArguments: transformGeoRadiusArguments.bind(undefined, 'GEORADIUS_RO'),
   transformReply: GEORADIUS.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUS_RO_WITH.spec.ts b/packages/client/lib/commands/GEORADIUS_RO_WITH.spec.ts
index cb0540d8a18..01d79954b64 100644
--- a/packages/client/lib/commands/GEORADIUS_RO_WITH.spec.ts
+++ b/packages/client/lib/commands/GEORADIUS_RO_WITH.spec.ts
@@ -3,6 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUS_RO_WITH from './GEORADIUS_RO_WITH';
 import { GEO_REPLY_WITH } from './GEOSEARCH_WITH';
 import { CommandArguments } from '../RESP/types';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUS_RO WITH', () => {
   it('transformArguments', () => {
@@ -10,7 +11,7 @@ describe('GEORADIUS_RO WITH', () => {
     expectedReply.preserve = ['WITHDIST'];
 
     assert.deepEqual(
-      GEORADIUS_RO_WITH.transformArguments('key', {
+      parseArgs(GEORADIUS_RO_WITH, 'key', {
         longitude: 1,
         latitude: 2
       }, 3, 'm', [GEO_REPLY_WITH.DISTANCE]),
diff --git a/packages/client/lib/commands/GEORADIUS_RO_WITH.ts b/packages/client/lib/commands/GEORADIUS_RO_WITH.ts
index 37cf594ce9d..084a9af8a8c 100644
--- a/packages/client/lib/commands/GEORADIUS_RO_WITH.ts
+++ b/packages/client/lib/commands/GEORADIUS_RO_WITH.ts
@@ -1,9 +1,11 @@
 import { Command } from '../RESP/types';
+import { parseGeoRadiusWithArguments } from './GEORADIUS_WITH';
 import GEORADIUS_WITH, { transformGeoRadiusWithArguments } from './GEORADIUS_WITH';
 
 export default {
   FIRST_KEY_INDEX: GEORADIUS_WITH.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseGeoRadiusWithArguments.bind(undefined, 'GEORADIUS_RO', true),
   transformArguments: transformGeoRadiusWithArguments.bind(undefined, 'GEORADIUS_RO'),
   transformReply: GEORADIUS_WITH.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUS_STORE.spec.ts b/packages/client/lib/commands/GEORADIUS_STORE.spec.ts
index 04a7d28aa95..9a9bcf37bcf 100644
--- a/packages/client/lib/commands/GEORADIUS_STORE.spec.ts
+++ b/packages/client/lib/commands/GEORADIUS_STORE.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUS_STORE from './GEORADIUS_STORE';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUS STORE', () => {
   describe('transformArguments', () => {
     it('STORE', () => {
       assert.deepEqual(
-        GEORADIUS_STORE.transformArguments('key', {
+        parseArgs(GEORADIUS_STORE, 'key', {
           longitude: 1,
           latitude: 2
         }, 3, 'm', 'destination'),
@@ -16,7 +17,7 @@ describe('GEORADIUS STORE', () => {
 
     it('STOREDIST', () => {
       assert.deepEqual(
-        GEORADIUS_STORE.transformArguments('key', {
+        parseArgs(GEORADIUS_STORE, 'key', {
           longitude: 1,
           latitude: 2 
         }, 3, 'm', 'destination', {
diff --git a/packages/client/lib/commands/GEORADIUS_STORE.ts b/packages/client/lib/commands/GEORADIUS_STORE.ts
index 3a553ebf8be..35d250e2d39 100644
--- a/packages/client/lib/commands/GEORADIUS_STORE.ts
+++ b/packages/client/lib/commands/GEORADIUS_STORE.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import GEORADIUS, { transformGeoRadiusArguments } from './GEORADIUS';
+import { CommandParser } from '../client/parser';
+import GEORADIUS, { parseGeoRadiusArguments } from './GEORADIUS';
 import { GeoCoordinates, GeoSearchOptions, GeoUnits } from './GEOSEARCH';
 
 export interface GeoRadiusStoreOptions extends GeoSearchOptions {
@@ -9,7 +10,8 @@ export interface GeoRadiusStoreOptions extends GeoSearchOptions {
 export default {
   FIRST_KEY_INDEX: GEORADIUS.FIRST_KEY_INDEX,
   IS_READ_ONLY: GEORADIUS.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     from: GeoCoordinates,
     radius: number,
@@ -17,15 +19,20 @@ export default {
     destination: RedisArgument,
     options?: GeoRadiusStoreOptions
   ) {
-    const args = transformGeoRadiusArguments('GEORADIUS', key, from, radius, unit, options);
-
+    parseGeoRadiusArguments('GEORADIUS', false, parser, key, from, radius, unit, options);
     if (options?.STOREDIST) {
-      args.push('STOREDIST', destination);
+      parser.pushVariadic(['STOREDIST', destination]);
     } else {
-      args.push('STORE', destination);
+      parser.pushVariadic(['STORE', destination])
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    from: GeoCoordinates,
+    radius: number,
+    unit: GeoUnits,
+    destination: RedisArgument,
+    options?: GeoRadiusStoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEORADIUS_WITH.spec.ts b/packages/client/lib/commands/GEORADIUS_WITH.spec.ts
index bdbfc9c1f3a..f514c9be96f 100644
--- a/packages/client/lib/commands/GEORADIUS_WITH.spec.ts
+++ b/packages/client/lib/commands/GEORADIUS_WITH.spec.ts
@@ -3,6 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
 import GEORADIUS_WITH from './GEORADIUS_WITH';
 import { GEO_REPLY_WITH } from './GEOSEARCH_WITH';
 import { CommandArguments } from '../RESP/types';
+import { parseArgs } from './generic-transformers';
 
 describe('GEORADIUS WITH', () => {
   it('transformArguments', () => {
@@ -10,7 +11,7 @@ describe('GEORADIUS WITH', () => {
     expectedReply.preserve = ['WITHDIST'];
 
     assert.deepEqual(
-      GEORADIUS_WITH.transformArguments('key', {
+      parseArgs(GEORADIUS_WITH, 'key', {
         longitude: 1,
         latitude: 2
       }, 3, 'm', [GEO_REPLY_WITH.DISTANCE]),
diff --git a/packages/client/lib/commands/GEORADIUS_WITH.ts b/packages/client/lib/commands/GEORADIUS_WITH.ts
index d72d8d49322..3384a9d8fd9 100644
--- a/packages/client/lib/commands/GEORADIUS_WITH.ts
+++ b/packages/client/lib/commands/GEORADIUS_WITH.ts
@@ -1,10 +1,13 @@
-import { CommandArguments, Command, RedisArgument } from '../RESP/types';
-import GEORADIUS, { transformGeoRadiusArguments } from './GEORADIUS';
+import { Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
+import GEORADIUS, { parseGeoRadiusArguments } from './GEORADIUS';
 import { GeoCoordinates, GeoSearchOptions, GeoUnits } from './GEOSEARCH';
 import GEOSEARCH_WITH, { GeoReplyWith } from './GEOSEARCH_WITH';
 
-export function transformGeoRadiusWithArguments(
+export function parseGeoRadiusWithArguments(
   command: RedisArgument,
+  cachable: boolean,
+  parser: CommandParser,
   key: RedisArgument,
   from: GeoCoordinates,
   radius: number,
@@ -12,22 +15,25 @@ export function transformGeoRadiusWithArguments(
   replyWith: Array<GeoReplyWith>,
   options?: GeoSearchOptions
 ) {
-  const args: CommandArguments = transformGeoRadiusArguments(
-    command,
-    key,
-    from,
-    radius,
-    unit,
-    options
-  );
-  args.push(...replyWith);
-  args.preserve = replyWith;
-  return args;
+  parseGeoRadiusArguments(command, cachable, parser, key, from, radius, unit, options)
+  parser.pushVariadic(replyWith);
+  parser.setPreserve(replyWith);
 }
 
+export function transformGeoRadiusWithArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  from: GeoCoordinates,
+  radius: number,
+  unit: GeoUnits,
+  replyWith: Array<GeoReplyWith>,
+  options?: GeoSearchOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: GEORADIUS.FIRST_KEY_INDEX,
   IS_READ_ONLY: GEORADIUS.IS_READ_ONLY,
+  parseCommand: parseGeoRadiusWithArguments.bind(undefined, 'GEORADIUS', false),
   transformArguments: transformGeoRadiusWithArguments.bind(undefined, 'GEORADIUS'),
   transformReply: GEOSEARCH_WITH.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEOSEARCH.spec.ts b/packages/client/lib/commands/GEOSEARCH.spec.ts
index 49f076880a6..4cd7e61a0ac 100644
--- a/packages/client/lib/commands/GEOSEARCH.spec.ts
+++ b/packages/client/lib/commands/GEOSEARCH.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOSEARCH from './GEOSEARCH';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOSEARCH', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,7 +9,7 @@ describe('GEOSEARCH', () => {
   describe('transformArguments', () => {
     it('FROMMEMBER, BYRADIUS, without options', () => {
       assert.deepEqual(
-        GEOSEARCH.transformArguments('key', 'member', {
+        parseArgs(GEOSEARCH, 'key', 'member', {
           radius: 1,
           unit: 'm'
         }),
@@ -18,7 +19,7 @@ describe('GEOSEARCH', () => {
 
     it('FROMLONLAT, BYBOX, without options', () => {
       assert.deepEqual(
-        GEOSEARCH.transformArguments('key', {
+        parseArgs(GEOSEARCH, 'key', {
           longitude: 1,
           latitude: 2
         }, {
@@ -32,7 +33,7 @@ describe('GEOSEARCH', () => {
 
     it('with SORT', () => {
       assert.deepEqual(
-        GEOSEARCH.transformArguments('key', 'member', {
+        parseArgs(GEOSEARCH, 'key', 'member', {
           radius: 1,
           unit: 'm'
         }, {
@@ -45,7 +46,7 @@ describe('GEOSEARCH', () => {
     describe('with COUNT', () => {
       it('number', () => {
         assert.deepEqual(
-          GEOSEARCH.transformArguments('key', 'member', {
+          parseArgs(GEOSEARCH, 'key', 'member', {
             radius: 1,
             unit: 'm'
           }, {
@@ -57,7 +58,7 @@ describe('GEOSEARCH', () => {
 
       it('with ANY', () => {
         assert.deepEqual(
-          GEOSEARCH.transformArguments('key', 'member', {
+          parseArgs(GEOSEARCH, 'key', 'member', {
             radius: 1,
             unit: 'm'
           }, {
diff --git a/packages/client/lib/commands/GEOSEARCH.ts b/packages/client/lib/commands/GEOSEARCH.ts
index c4deaa37e6c..ee3938bd525 100644
--- a/packages/client/lib/commands/GEOSEARCH.ts
+++ b/packages/client/lib/commands/GEOSEARCH.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, CommandArguments, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type GeoUnits = 'm' | 'km' | 'mi' | 'ft';
 
@@ -22,30 +23,36 @@ export interface GeoSearchByBox {
 
 export type GeoSearchBy = GeoSearchByRadius | GeoSearchByBox;
 
-export function pushGeoSearchArguments(
-  args: CommandArguments,
+export function parseGeoSearchArguments(
+  parser: CommandParser,
+  command: RedisArgument,
   key: RedisArgument,
   from: GeoSearchFrom,
   by: GeoSearchBy,
-  options?: GeoSearchOptions
+  options?: GeoSearchOptions,
+  store?: RedisArgument
 ) {
-  args.push(key);
+  parser.push(command);
+
+  if (store !== undefined) {
+    parser.pushKey(store);
+  }
+
+  parser.pushKey(key);
 
   if (typeof from === 'string' || from instanceof Buffer) {
-    args.push('FROMMEMBER', from);
+    parser.pushVariadic(['FROMMEMBER', from]);
   } else {
-    args.push('FROMLONLAT', from.longitude.toString(), from.latitude.toString());
+    parser.pushVariadic(['FROMLONLAT', from.longitude.toString(), from.latitude.toString()]);
   }
 
   if ('radius' in by) {
-    args.push('BYRADIUS', by.radius.toString(), by.unit);
+    parser.pushVariadic(['BYRADIUS', by.radius.toString(), by.unit]);
   } else {
-    args.push('BYBOX', by.width.toString(), by.height.toString(), by.unit);
+    parser.pushVariadic(['BYBOX', by.width.toString(), by.height.toString(), by.unit]);
   }
 
-  pushGeoSearchOptions(args, options);
-
-  return args;
+  parseGeoSearchOptions(parser, options);
 }
 
 export type GeoCountArgument = number | {
@@ -58,22 +65,22 @@ export interface GeoSearchOptions {
   COUNT?: GeoCountArgument;
 }
 
-export function pushGeoSearchOptions(
-  args: CommandArguments,
+export function parseGeoSearchOptions(
+  parser: CommandParser,
   options?: GeoSearchOptions
 ) {
   if (options?.SORT) {
-    args.push(options.SORT);
+    parser.push(options.SORT);
   }
 
   if (options?.COUNT) {
     if (typeof options.COUNT === 'number') {
-      args.push('COUNT', options.COUNT.toString());
+      parser.pushVariadic(['COUNT', options.COUNT.toString()]);
     } else {
-      args.push('COUNT', options.COUNT.value.toString());
+      parser.pushVariadic(['COUNT', options.COUNT.value.toString()]);
   
       if (options.COUNT.ANY) {
-        args.push('ANY');
+        parser.push('ANY');
       }
     }
   }
@@ -82,13 +89,20 @@ export function pushGeoSearchOptions(
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     from: GeoSearchFrom,
     by: GeoSearchBy,
     options?: GeoSearchOptions
   ) {
-    return pushGeoSearchArguments(['GEOSEARCH'], key, from, by, options);
+    parseGeoSearchArguments(parser, 'GEOSEARCH', key, from, by, options);
   },
+  transformArguments(
+    key: RedisArgument,
+    from: GeoSearchFrom,
+    by: GeoSearchBy,
+    options?: GeoSearchOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEOSEARCHSTORE.spec.ts b/packages/client/lib/commands/GEOSEARCHSTORE.spec.ts
index c66d3e8e45e..b8427ae0412 100644
--- a/packages/client/lib/commands/GEOSEARCHSTORE.spec.ts
+++ b/packages/client/lib/commands/GEOSEARCHSTORE.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOSEARCHSTORE from './GEOSEARCHSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOSEARCHSTORE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,7 +9,7 @@ describe('GEOSEARCHSTORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        GEOSEARCHSTORE.transformArguments('source', 'destination', 'member', {
+        parseArgs(GEOSEARCHSTORE, 'source', 'destination', 'member', {
           radius: 1,
           unit: 'm'
         }),
@@ -18,7 +19,7 @@ describe('GEOSEARCHSTORE', () => {
 
     it('with STOREDIST', () => {
       assert.deepEqual(
-        GEOSEARCHSTORE.transformArguments('destination', 'source', 'member', {
+        parseArgs(GEOSEARCHSTORE, 'destination', 'source', 'member', {
           radius: 1,
           unit: 'm'
         }, {
diff --git a/packages/client/lib/commands/GEOSEARCHSTORE.ts b/packages/client/lib/commands/GEOSEARCHSTORE.ts
index 15635560217..49820199a22 100644
--- a/packages/client/lib/commands/GEOSEARCHSTORE.ts
+++ b/packages/client/lib/commands/GEOSEARCHSTORE.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { GeoSearchFrom, GeoSearchBy, GeoSearchOptions, pushGeoSearchArguments } from './GEOSEARCH';
+import { CommandParser } from '../client/parser';
+import { GeoSearchFrom, GeoSearchBy, GeoSearchOptions, parseGeoSearchArguments } from './GEOSEARCH';
 
 export interface GeoSearchStoreOptions extends GeoSearchOptions {
   STOREDIST?: boolean;
@@ -8,20 +9,26 @@ export interface GeoSearchStoreOptions extends GeoSearchOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     destination: RedisArgument,
     source: RedisArgument,
     from: GeoSearchFrom,
     by: GeoSearchBy,
     options?: GeoSearchStoreOptions
   ) {
-    const args = pushGeoSearchArguments(['GEOSEARCHSTORE', destination], source, from, by, options);
+    parseGeoSearchArguments(parser, 'GEOSEARCHSTORE', source, from, by, options, destination);
 
     if (options?.STOREDIST) {
-      args.push('STOREDIST');
+      parser.push('STOREDIST');
     }
-
-    return args;
   },
+  transformArguments(
+    destination: RedisArgument,
+    source: RedisArgument,
+    from: GeoSearchFrom,
+    by: GeoSearchBy,
+    options?: GeoSearchStoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GEOSEARCH_WITH.spec.ts b/packages/client/lib/commands/GEOSEARCH_WITH.spec.ts
index e27fb295aaf..973e5d5827f 100644
--- a/packages/client/lib/commands/GEOSEARCH_WITH.spec.ts
+++ b/packages/client/lib/commands/GEOSEARCH_WITH.spec.ts
@@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GEOSEARCH_WITH, { GEO_REPLY_WITH } from './GEOSEARCH_WITH';
 import { CommandArguments } from '../RESP/types';
+import { parseArgs } from './generic-transformers';
 
 describe('GEOSEARCH WITH', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -11,7 +12,7 @@ describe('GEOSEARCH WITH', () => {
     expectedReply.preserve = ['WITHDIST'];
 
     assert.deepEqual(
-      GEOSEARCH_WITH.transformArguments('key', 'member', {
+      parseArgs(GEOSEARCH_WITH, 'key', 'member', {
         radius: 1,
         unit: 'm'
       }, [GEO_REPLY_WITH.DISTANCE]),
diff --git a/packages/client/lib/commands/GEOSEARCH_WITH.ts b/packages/client/lib/commands/GEOSEARCH_WITH.ts
index 19088230f0f..f55ba3bda6d 100644
--- a/packages/client/lib/commands/GEOSEARCH_WITH.ts
+++ b/packages/client/lib/commands/GEOSEARCH_WITH.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, NumberReply, DoubleReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import GEOSEARCH, { GeoSearchBy, GeoSearchFrom, GeoSearchOptions } from './GEOSEARCH';
 
 export const GEO_REPLY_WITH = {
@@ -22,18 +23,25 @@ export interface GeoReplyWithMember {
 export default {
   FIRST_KEY_INDEX: GEOSEARCH.FIRST_KEY_INDEX,
   IS_READ_ONLY: GEOSEARCH.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     from: GeoSearchFrom,
     by: GeoSearchBy,
     replyWith: Array<GeoReplyWith>,
     options?: GeoSearchOptions
   ) {
-    const args = GEOSEARCH.transformArguments(key, from, by, options);
-    args.push(...replyWith);
-    args.preserve = replyWith;
-    return args;
+    GEOSEARCH.parseCommand(parser, key, from, by, options);
+    parser.pushVariadic(replyWith);
+    parser.setPreserve(replyWith);
   },
+  transformArguments(
+    key: RedisArgument,
+    from: GeoSearchFrom,
+    by: GeoSearchBy,
+    replyWith: Array<GeoReplyWith>,
+    options?: GeoSearchOptions
+  ) { return [] },
   transformReply(
     reply: UnwrapReply<ArrayReply<TuplesReply<[BlobStringReply, ...Array<any>]>>>,
     replyWith: Array<GeoReplyWith>
diff --git a/packages/client/lib/commands/GETBIT.spec.ts b/packages/client/lib/commands/GETBIT.spec.ts
index ac39222b918..66d2798313c 100644
--- a/packages/client/lib/commands/GETBIT.spec.ts
+++ b/packages/client/lib/commands/GETBIT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GETBIT from './GETBIT';
+import { parseArgs } from './generic-transformers';
 
 describe('GETBIT', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      GETBIT.transformArguments('key', 0),
+      parseArgs(GETBIT, 'key', 0),
       ['GETBIT', 'key', '0']
     );
   });
diff --git a/packages/client/lib/commands/GETBIT.ts b/packages/client/lib/commands/GETBIT.ts
index d8ece8f523a..cc22223d201 100644
--- a/packages/client/lib/commands/GETBIT.ts
+++ b/packages/client/lib/commands/GETBIT.ts
@@ -1,11 +1,16 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { BitValue } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, offset: number) {
-    return ['GETBIT', key, offset.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, offset: number) {
+    parser.setCachable();
+    parser.push('GETBIT');
+    parser.pushKey(key);
+    parser.push(offset.toString());
   },
+  transformArguments(key: RedisArgument, offset: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply<BitValue>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GETDEL.spec.ts b/packages/client/lib/commands/GETDEL.spec.ts
index 311f15e554d..15ad5918008 100644
--- a/packages/client/lib/commands/GETDEL.spec.ts
+++ b/packages/client/lib/commands/GETDEL.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GETDEL from './GETDEL';
+import { parseArgs } from './generic-transformers';
 
 describe('GETDEL', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      GETDEL.transformArguments('key'),
+      parseArgs(GETDEL, 'key'),
       ['GETDEL', 'key']
     );
   });
diff --git a/packages/client/lib/commands/GETDEL.ts b/packages/client/lib/commands/GETDEL.ts
index c11fd047df4..3a7c8f02ad9 100644
--- a/packages/client/lib/commands/GETDEL.ts
+++ b/packages/client/lib/commands/GETDEL.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['GETDEL', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('GETDEL');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GETEX.spec.ts b/packages/client/lib/commands/GETEX.spec.ts
index 302d034b961..5965d8f196f 100644
--- a/packages/client/lib/commands/GETEX.spec.ts
+++ b/packages/client/lib/commands/GETEX.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GETEX from './GETEX';
+import { parseArgs } from './generic-transformers';
 
 describe('GETEX', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,7 +9,7 @@ describe('GETEX', () => {
   describe('transformArguments', () => {
     it('EX | PX', () => {
       assert.deepEqual(
-        GETEX.transformArguments('key', {
+        parseArgs(GETEX, 'key', {
           type: 'EX',
           value: 1
         }),
@@ -18,7 +19,7 @@ describe('GETEX', () => {
 
     it('EX (backwards compatibility)', () => {
       assert.deepEqual(
-        GETEX.transformArguments('key', {
+        parseArgs(GETEX, 'key', {
           EX: 1
         }),
         ['GETEX', 'key', 'EX', '1']
@@ -27,7 +28,7 @@ describe('GETEX', () => {
 
     it('PX (backwards compatibility)', () => {
       assert.deepEqual(
-        GETEX.transformArguments('key', {
+        parseArgs(GETEX, 'key', {
           PX: 1
         }),
         ['GETEX', 'key', 'PX', '1']
@@ -37,7 +38,7 @@ describe('GETEX', () => {
     describe('EXAT | PXAT', () => {
       it('number', () => {
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             type: 'EXAT',
             value: 1
           }),
@@ -48,7 +49,7 @@ describe('GETEX', () => {
       it('date', () => {
         const d = new Date();
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             EXAT: d
           }),
           ['GETEX', 'key', 'EXAT', Math.floor(d.getTime() / 1000).toString()]
@@ -59,7 +60,7 @@ describe('GETEX', () => {
     describe('EXAT (backwards compatibility)', () => {
       it('number', () => {
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             EXAT: 1
           }),
           ['GETEX', 'key', 'EXAT', '1']
@@ -69,7 +70,7 @@ describe('GETEX', () => {
       it('date', () => {
         const d = new Date();
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             EXAT: d
           }),
           ['GETEX', 'key', 'EXAT', Math.floor(d.getTime() / 1000).toString()]
@@ -80,7 +81,7 @@ describe('GETEX', () => {
     describe('PXAT (backwards compatibility)', () => {
       it('number', () => {
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             PXAT: 1
           }),
           ['GETEX', 'key', 'PXAT', '1']
@@ -90,7 +91,7 @@ describe('GETEX', () => {
       it('date', () => {
         const d = new Date();
         assert.deepEqual(
-          GETEX.transformArguments('key', {
+          parseArgs(GETEX, 'key', {
             PXAT: d
           }),
           ['GETEX', 'key', 'PXAT', d.getTime().toString()]
@@ -100,7 +101,7 @@ describe('GETEX', () => {
 
     it('PERSIST (backwards compatibility)', () => {
       assert.deepEqual(
-        GETEX.transformArguments('key', {
+        parseArgs(GETEX, 'key', {
           PERSIST: true
         }),
         ['GETEX', 'key', 'PERSIST']
diff --git a/packages/client/lib/commands/GETEX.ts b/packages/client/lib/commands/GETEX.ts
index 8244350eddb..59d1b1c8d48 100644
--- a/packages/client/lib/commands/GETEX.ts
+++ b/packages/client/lib/commands/GETEX.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformEXAT, transformPXAT } from './generic-transformers';
 
 export type GetExOptions = {
@@ -39,40 +40,40 @@ export type GetExOptions = {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options: GetExOptions) {
-    const args = ['GETEX', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options: GetExOptions) {
+    parser.push('GETEX');
+    parser.pushKey(key);
 
     if ('type' in options) {
       switch (options.type) {
         case 'EX':
         case 'PX':
-          args.push(options.type, options.value.toString());
+          parser.pushVariadic([options.type, options.value.toString()]);
           break;
         
         case 'EXAT':
         case 'PXAT':
-          args.push(options.type, transformEXAT(options.value));
+          parser.pushVariadic([options.type, transformEXAT(options.value)]);
           break;
 
         case 'PERSIST':
-          args.push('PERSIST');
+          parser.push('PERSIST');
           break;
       }
     } else {
       if ('EX' in options) {
-        args.push('EX', options.EX.toString());
+        parser.pushVariadic(['EX', options.EX.toString()]);
       } else if ('PX' in options) {
-        args.push('PX', options.PX.toString());
+        parser.pushVariadic(['PX', options.PX.toString()]);
       } else if ('EXAT' in options) {
-        args.push('EXAT', transformEXAT(options.EXAT));
+        parser.pushVariadic(['EXAT', transformEXAT(options.EXAT)]);
       } else if ('PXAT' in options) {
-        args.push('PXAT', transformPXAT(options.PXAT));
+        parser.pushVariadic(['PXAT', transformPXAT(options.PXAT)]);
       } else { // PERSIST
-        args.push('PERSIST');
+        parser.push('PERSIST');
       }
     }
-    
-    return args;
   },
+  transformArguments(key: RedisArgument, options: GetExOptions) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GETRANGE.spec.ts b/packages/client/lib/commands/GETRANGE.spec.ts
index 2aac1ca16d9..8a8e7dde038 100644
--- a/packages/client/lib/commands/GETRANGE.spec.ts
+++ b/packages/client/lib/commands/GETRANGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GETRANGE from './GETRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('GETRANGE', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      GETRANGE.transformArguments('key', 0, -1),
+      parseArgs(GETRANGE, 'key', 0, -1),
       ['GETRANGE', 'key', '0', '-1']
     );
   });
diff --git a/packages/client/lib/commands/GETRANGE.ts b/packages/client/lib/commands/GETRANGE.ts
index e5357cd120b..18534473720 100644
--- a/packages/client/lib/commands/GETRANGE.ts
+++ b/packages/client/lib/commands/GETRANGE.ts
@@ -1,10 +1,16 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, start: number, end: number) {
-    return ['GETRANGE', key, start.toString(), end.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, start: number, end: number) {
+    parser.setCachable();
+    parser.push('GETRANGE');
+    parser.pushKey(key);
+    parser.push(start.toString());
+    parser.push(end.toString());
   },
+  transformArguments(key: RedisArgument, start: number, end: number) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/GETSET.spec.ts b/packages/client/lib/commands/GETSET.spec.ts
index 6583ec34f75..5b162c16cc4 100644
--- a/packages/client/lib/commands/GETSET.spec.ts
+++ b/packages/client/lib/commands/GETSET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GETSET from './GETSET';
+import { parseArgs } from './generic-transformers';
 
 describe('GETSET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      GETSET.transformArguments('key', 'value'),
+      parseArgs(GETSET, 'key', 'value'),
       ['GETSET', 'key', 'value']
     );
   });
diff --git a/packages/client/lib/commands/GETSET.ts b/packages/client/lib/commands/GETSET.ts
index bbe920181b2..87983ab4145 100644
--- a/packages/client/lib/commands/GETSET.ts
+++ b/packages/client/lib/commands/GETSET.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, value: RedisArgument) {
-    return ['GETSET', key, value];
+  parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) {
+    parser.push('GETSET');
+    parser.pushKey(key);
+    parser.push(value);
   },
+  transformArguments(key: RedisArgument, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HDEL.spec.ts b/packages/client/lib/commands/HDEL.spec.ts
index 9f69485d9fe..767d916e147 100644
--- a/packages/client/lib/commands/HDEL.spec.ts
+++ b/packages/client/lib/commands/HDEL.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HDEL from './HDEL';
+import { parseArgs } from './generic-transformers';
 
 describe('HDEL', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        HDEL.transformArguments('key', 'field'),
+        parseArgs(HDEL, 'key', 'field'),
         ['HDEL', 'key', 'field']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        HDEL.transformArguments('key', ['1', '2']),
+        parseArgs(HDEL, 'key', ['1', '2']),
         ['HDEL', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/HDEL.ts b/packages/client/lib/commands/HDEL.ts
index 64aa55edda6..62e80b4d09b 100644
--- a/packages/client/lib/commands/HDEL.ts
+++ b/packages/client/lib/commands/HDEL.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, field: RedisVariadicArgument) {
-    return pushVariadicArguments(['HDEL', key], field);
+  parseCommand(parser: CommandParser, key: RedisArgument, field: RedisVariadicArgument) {
+    parser.push('HDEL');
+    parser.pushKey(key);
+    parser.pushVariadic(field);
   },
+  transformArguments(key: RedisArgument, field: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HELLO.spec.ts b/packages/client/lib/commands/HELLO.spec.ts
index a0f088a4ba6..170a21a6983 100644
--- a/packages/client/lib/commands/HELLO.spec.ts
+++ b/packages/client/lib/commands/HELLO.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HELLO from './HELLO';
+import { parseArgs } from './generic-transformers';
 
 describe('HELLO', () => {
   testUtils.isVersionGreaterThanHook([6]);
@@ -8,21 +9,21 @@ describe('HELLO', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        HELLO.transformArguments(),
+        parseArgs(HELLO),
         ['HELLO']
       );
     });
 
     it('with protover', () => {
       assert.deepEqual(
-        HELLO.transformArguments(3),
+        parseArgs(HELLO, 3),
         ['HELLO', '3']
       );
     });
 
     it('with protover, AUTH', () => {
       assert.deepEqual(
-        HELLO.transformArguments(3, {
+        parseArgs(HELLO, 3, {
           AUTH: {
             username: 'username',
             password: 'password'
@@ -34,7 +35,7 @@ describe('HELLO', () => {
 
     it('with protover, SETNAME', () => {
       assert.deepEqual(
-        HELLO.transformArguments(3, {
+        parseArgs(HELLO, 3, {
           SETNAME: 'name'
         }),
         ['HELLO', '3', 'SETNAME', 'name']
@@ -43,7 +44,7 @@ describe('HELLO', () => {
 
     it('with protover, AUTH, SETNAME', () => {
       assert.deepEqual(
-        HELLO.transformArguments(3, {
+        parseArgs(HELLO, 3, {
           AUTH: {
             username: 'username',
             password: 'password'
diff --git a/packages/client/lib/commands/HELLO.ts b/packages/client/lib/commands/HELLO.ts
index 0fb2960d028..06e50543860 100644
--- a/packages/client/lib/commands/HELLO.ts
+++ b/packages/client/lib/commands/HELLO.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, RespVersions, TuplesToMapReply, BlobStringReply, NumberReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface HelloOptions {
   protover?: RespVersions;
@@ -20,30 +21,33 @@ export type HelloReply = TuplesToMapReply<[
 ]>;
 
 export default {
-  transformArguments(protover?: RespVersions, options?: HelloOptions) {
-    const args: Array<RedisArgument> = ['HELLO'];
+  parseCommand(parser: CommandParser, protover?: RespVersions, options?: HelloOptions) {
+    parser.push('HELLO');
 
     if (protover) {
-      args.push(protover.toString());
+      parser.push(protover.toString());
 
       if (options?.AUTH) {
-        args.push(
-          'AUTH',
-          options.AUTH.username,
-          options.AUTH.password
+        parser.pushVariadic(
+          [
+            'AUTH',
+            options.AUTH.username,
+            options.AUTH.password
+          ]
         );
       }
   
       if (options?.SETNAME) {
-        args.push(
-          'SETNAME',
-          options.SETNAME
+        parser.pushVariadic(
+          [
+            'SETNAME',
+            options.SETNAME
+          ]
         );
       }
     }
-    
-    return args;
   },
+  transformArguments(protover?: RespVersions, options?: HelloOptions) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<HelloReply>>) => ({
       server: reply[1],
diff --git a/packages/client/lib/commands/HEXISTS.spec.ts b/packages/client/lib/commands/HEXISTS.spec.ts
index 69ca6fa765f..acd462ab7e2 100644
--- a/packages/client/lib/commands/HEXISTS.spec.ts
+++ b/packages/client/lib/commands/HEXISTS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HEXISTS from './HEXISTS';
+import { parseArgs } from './generic-transformers';
 
 describe('HEXISTS', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      HEXISTS.transformArguments('key', 'field'),
+      parseArgs(HEXISTS, 'key', 'field'),
       ['HEXISTS', 'key', 'field']
     );
   });
diff --git a/packages/client/lib/commands/HEXISTS.ts b/packages/client/lib/commands/HEXISTS.ts
index dc7e937ee78..b22f7771523 100644
--- a/packages/client/lib/commands/HEXISTS.ts
+++ b/packages/client/lib/commands/HEXISTS.ts
@@ -1,10 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, field: RedisArgument) {
-    return ['HEXISTS', key, field];
+  parseCommand(parser: CommandParser, key: RedisArgument, field: RedisArgument) {
+    parser.setCachable();
+    parser.push('HEXISTS');
+    parser.pushKey(key);
+    parser.push(field);
   },
+  transformArguments(key: RedisArgument, field: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply<0 | 1>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HGET.spec.ts b/packages/client/lib/commands/HGET.spec.ts
index 397f22b5604..47061876aea 100644
--- a/packages/client/lib/commands/HGET.spec.ts
+++ b/packages/client/lib/commands/HGET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HGET from './HGET';
+import { parseArgs } from './generic-transformers';
 
 describe('HGET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HGET.transformArguments('key', 'field'),
+      parseArgs(HGET, 'key', 'field'),
       ['HGET', 'key', 'field']
     );
   });
diff --git a/packages/client/lib/commands/HGET.ts b/packages/client/lib/commands/HGET.ts
index d83f84e24fa..0f0d8f9d8ea 100644
--- a/packages/client/lib/commands/HGET.ts
+++ b/packages/client/lib/commands/HGET.ts
@@ -1,10 +1,15 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, field: RedisArgument) {
-    return ['HGET', key, field];
+  parseCommand(parser: CommandParser, key: RedisArgument, field: RedisArgument) {
+    parser.setCachable();
+    parser.push('HGET');
+    parser.pushKey(key);
+    parser.push(field);
   },
+  transformArguments(key: RedisArgument, field: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HGETALL.ts b/packages/client/lib/commands/HGETALL.ts
index f1f0ac50bcb..1d6da55d21b 100644
--- a/packages/client/lib/commands/HGETALL.ts
+++ b/packages/client/lib/commands/HGETALL.ts
@@ -1,12 +1,16 @@
 import { RedisArgument, MapReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformTuplesReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['HGETALL', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('HGETALL');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   TRANSFORM_LEGACY_REPLY: true,
   transformReply: {
     2: transformTuplesReply,
diff --git a/packages/client/lib/commands/HINCRBY.spec.ts b/packages/client/lib/commands/HINCRBY.spec.ts
index 7718fe955eb..ad382d97a99 100644
--- a/packages/client/lib/commands/HINCRBY.spec.ts
+++ b/packages/client/lib/commands/HINCRBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HINCRBY from './HINCRBY';
+import { parseArgs } from './generic-transformers';
 
 describe('HINCRBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HINCRBY.transformArguments('key', 'field', 1),
+      parseArgs(HINCRBY, 'key', 'field', 1),
       ['HINCRBY', 'key', 'field', '1']
     );
   });
diff --git a/packages/client/lib/commands/HINCRBY.ts b/packages/client/lib/commands/HINCRBY.ts
index cb7f62ebef5..dc78ceef0f9 100644
--- a/packages/client/lib/commands/HINCRBY.ts
+++ b/packages/client/lib/commands/HINCRBY.ts
@@ -1,18 +1,22 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     field: RedisArgument,
     increment: number
   ) {
-    return [
-      'HINCRBY',
-      key,
-      field,
-      increment.toString()
-    ];
+    parser.push('HINCRBY');
+    parser.pushKey(key);
+    parser.pushVariadic([field, increment.toString()]);
   },
+  transformArguments(
+    key: RedisArgument,
+    field: RedisArgument,
+    increment: number
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HINCRBYFLOAT.spec.ts b/packages/client/lib/commands/HINCRBYFLOAT.spec.ts
index 6c265dc6d10..2edbd6f9477 100644
--- a/packages/client/lib/commands/HINCRBYFLOAT.spec.ts
+++ b/packages/client/lib/commands/HINCRBYFLOAT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HINCRBYFLOAT from './HINCRBYFLOAT';
+import { parseArgs } from './generic-transformers';
 
 describe('HINCRBYFLOAT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HINCRBYFLOAT.transformArguments('key', 'field', 1.5),
+      parseArgs(HINCRBYFLOAT, 'key', 'field', 1.5),
       ['HINCRBYFLOAT', 'key', 'field', '1.5']
     );
   });
diff --git a/packages/client/lib/commands/HINCRBYFLOAT.ts b/packages/client/lib/commands/HINCRBYFLOAT.ts
index a4eea75c827..cb67db089aa 100644
--- a/packages/client/lib/commands/HINCRBYFLOAT.ts
+++ b/packages/client/lib/commands/HINCRBYFLOAT.ts
@@ -1,18 +1,22 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     field: RedisArgument,
     increment: number
   ) {
-    return [
-      'HINCRBYFLOAT',
-      key,
-      field,
-      increment.toString()
-    ];
+    parser.push('HINCRBYFLOAT');
+    parser.pushKey(key);
+    parser.pushVariadic([field, increment.toString()]);
   },
+  transformArguments(
+    key: RedisArgument,
+    field: RedisArgument,
+    increment: number
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HKEYS.spec.ts b/packages/client/lib/commands/HKEYS.spec.ts
index dada7b4d6fd..58445696d20 100644
--- a/packages/client/lib/commands/HKEYS.spec.ts
+++ b/packages/client/lib/commands/HKEYS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HKEYS from './HKEYS';
+import { parseArgs } from './generic-transformers';
 
 describe('HKEYS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HKEYS.transformArguments('key'),
+      parseArgs(HKEYS, 'key'),
       ['HKEYS', 'key']
     );
   });
diff --git a/packages/client/lib/commands/HKEYS.ts b/packages/client/lib/commands/HKEYS.ts
index 00af43f7a40..ed0f63094e3 100644
--- a/packages/client/lib/commands/HKEYS.ts
+++ b/packages/client/lib/commands/HKEYS.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['HKEYS', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('HKEYS')
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HLEN.spec.ts b/packages/client/lib/commands/HLEN.spec.ts
index 2457a261299..640e461ad07 100644
--- a/packages/client/lib/commands/HLEN.spec.ts
+++ b/packages/client/lib/commands/HLEN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HLEN from './HLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('HLEN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HLEN.transformArguments('key'),
+      parseArgs(HLEN, 'key'),
       ['HLEN', 'key']
     );
   });
diff --git a/packages/client/lib/commands/HLEN.ts b/packages/client/lib/commands/HLEN.ts
index 8f156d303e2..6301b477c5a 100644
--- a/packages/client/lib/commands/HLEN.ts
+++ b/packages/client/lib/commands/HLEN.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['HLEN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('HLEN');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HMGET.spec.ts b/packages/client/lib/commands/HMGET.spec.ts
index 99d94a6d375..8cc90e4abd5 100644
--- a/packages/client/lib/commands/HMGET.spec.ts
+++ b/packages/client/lib/commands/HMGET.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HMGET from './HMGET';
+import { parseArgs } from './generic-transformers';
 
 describe('HMGET', () => {
-  describe('transformArguments', () => {
+  describe('parseCommand', () => {
     it('string', () => {
       assert.deepEqual(
-        HMGET.transformArguments('key', 'field'),
+        parseArgs(HMGET, 'key', 'field'),
         ['HMGET', 'key', 'field']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        HMGET.transformArguments('key', ['field1', 'field2']),
+        parseArgs(HMGET, 'key', ['field1', 'field2']),
         ['HMGET', 'key', 'field1', 'field2']
       );
     });
diff --git a/packages/client/lib/commands/HMGET.ts b/packages/client/lib/commands/HMGET.ts
index df28a64be09..b7cb96672d9 100644
--- a/packages/client/lib/commands/HMGET.ts
+++ b/packages/client/lib/commands/HMGET.ts
@@ -1,14 +1,16 @@
 import { RedisArgument, ArrayReply, BlobStringReply, NullReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    fields: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['HMGET', key], fields);
+  parseCommand(parser: CommandParser, key: RedisArgument, fields: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('HMGET');
+    parser.pushKey(key);
+    parser.pushVariadic(fields);
   },
+  transformArguments(key: RedisArgument, fields: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HRANDFIELD.spec.ts b/packages/client/lib/commands/HRANDFIELD.spec.ts
index 33f2d281803..151636057a0 100644
--- a/packages/client/lib/commands/HRANDFIELD.spec.ts
+++ b/packages/client/lib/commands/HRANDFIELD.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HRANDFIELD from './HRANDFIELD';
+import { parseArgs } from './generic-transformers';
 
 describe('HRANDFIELD', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      HRANDFIELD.transformArguments('key'),
+      parseArgs(HRANDFIELD, 'key'),
       ['HRANDFIELD', 'key']
     );
   });
diff --git a/packages/client/lib/commands/HRANDFIELD.ts b/packages/client/lib/commands/HRANDFIELD.ts
index be878e244a0..c81cb0e6302 100644
--- a/packages/client/lib/commands/HRANDFIELD.ts
+++ b/packages/client/lib/commands/HRANDFIELD.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['HRANDFIELD', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('HRANDFIELD');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HRANDFIELD_COUNT.spec.ts b/packages/client/lib/commands/HRANDFIELD_COUNT.spec.ts
index 99788dc4962..ee3fc984d55 100644
--- a/packages/client/lib/commands/HRANDFIELD_COUNT.spec.ts
+++ b/packages/client/lib/commands/HRANDFIELD_COUNT.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HRANDFIELD_COUNT from './HRANDFIELD_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('HRANDFIELD COUNT', () => {
   testUtils.isVersionGreaterThanHook([6, 2, 5]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      HRANDFIELD_COUNT.transformArguments('key', 1),
+      parseArgs(HRANDFIELD_COUNT, 'key', 1),
       ['HRANDFIELD', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/HRANDFIELD_COUNT.ts b/packages/client/lib/commands/HRANDFIELD_COUNT.ts
index 4b6f42a115b..f61deebca16 100644
--- a/packages/client/lib/commands/HRANDFIELD_COUNT.ts
+++ b/packages/client/lib/commands/HRANDFIELD_COUNT.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['HRANDFIELD', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('HRANDFIELD');
+    parser.pushKey(key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.ts b/packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.ts
index ab36183c4ad..e9c97761d53 100644
--- a/packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.ts
+++ b/packages/client/lib/commands/HRANDFIELD_COUNT_WITHVALUES.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type HRandFieldCountWithValuesReply = Array<{
   field: BlobStringReply;
@@ -8,9 +9,12 @@ export type HRandFieldCountWithValuesReply = Array<{
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['HRANDFIELD', key, count.toString(), 'WITHVALUES'];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('HRANDFIELD');
+    parser.pushKey(key);
+    parser.pushVariadic([count.toString(), 'WITHVALUES']);
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: {
     2: (rawReply: UnwrapReply<ArrayReply<BlobStringReply>>) => {
       const reply: HRandFieldCountWithValuesReply = [];
diff --git a/packages/client/lib/commands/HSCAN.spec.ts b/packages/client/lib/commands/HSCAN.spec.ts
index 463d557f743..37ae4edba10 100644
--- a/packages/client/lib/commands/HSCAN.spec.ts
+++ b/packages/client/lib/commands/HSCAN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import HSCAN from './HSCAN';
 
 describe('HSCAN', () => {
   describe('transformArguments', () => {
     it('cusror only', () => {
       assert.deepEqual(
-        HSCAN.transformArguments('key', '0'),
+        parseArgs(HSCAN, 'key', '0'),
         ['HSCAN', 'key', '0']
       );
     });
 
     it('with MATCH', () => {
       assert.deepEqual(
-        HSCAN.transformArguments('key', '0', {
+        parseArgs(HSCAN, 'key', '0', {
           MATCH: 'pattern'
         }),
         ['HSCAN', 'key', '0', 'MATCH', 'pattern']
@@ -22,7 +23,7 @@ describe('HSCAN', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        HSCAN.transformArguments('key', '0', {
+        parseArgs(HSCAN, 'key', '0', {
           COUNT: 1
         }),
         ['HSCAN', 'key', '0', 'COUNT', '1']
@@ -31,7 +32,7 @@ describe('HSCAN', () => {
 
     it('with MATCH & COUNT', () => {
       assert.deepEqual(
-        HSCAN.transformArguments('key', '0', {
+        parseArgs(HSCAN, 'key', '0', {
           MATCH: 'pattern',
           COUNT: 1
         }),
diff --git a/packages/client/lib/commands/HSCAN.ts b/packages/client/lib/commands/HSCAN.ts
index db52db99fef..24e7023d509 100644
--- a/packages/client/lib/commands/HSCAN.ts
+++ b/packages/client/lib/commands/HSCAN.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
-import { ScanCommonOptions, pushScanArguments } from './SCAN';
+import { CommandParser } from '../client/parser';
+import { ScanCommonOptions, parseScanArguments } from './SCAN';
 
 export interface HScanEntry {
   field: BlobStringReply;
@@ -9,13 +10,21 @@ export interface HScanEntry {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     cursor: RedisArgument,
     options?: ScanCommonOptions
   ) {
-    return pushScanArguments(['HSCAN', key], cursor, options);
+    parser.push('HSCAN');
+    parser.pushKey(key);
+    parseScanArguments(parser, cursor, options);
   },
+  transformArguments(
+    key: RedisArgument,
+    cursor: RedisArgument,
+    options?: ScanCommonOptions
+  ) { return []; },
   transformReply([cursor, rawEntries]: [BlobStringReply, Array<BlobStringReply>]) {
     const entries = [];
     let i = 0;
diff --git a/packages/client/lib/commands/HSET.spec.ts b/packages/client/lib/commands/HSET.spec.ts
index eb5fdcd9b32..2cb53e6485a 100644
--- a/packages/client/lib/commands/HSET.spec.ts
+++ b/packages/client/lib/commands/HSET.spec.ts
@@ -1,27 +1,28 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HSET from './HSET';
+import { parseArgs } from './generic-transformers';
 
 describe('HSET', () => {
   describe('transformArguments', () => {
     describe('field, value', () => {
       it('string', () => {
         assert.deepEqual(
-          HSET.transformArguments('key', 'field', 'value'),
+          parseArgs(HSET, 'key', 'field', 'value'),
           ['HSET', 'key', 'field', 'value']
         );
       });
 
       it('number', () => {
         assert.deepEqual(
-          HSET.transformArguments('key', 1, 2),
+          parseArgs(HSET, 'key', 1, 2),
           ['HSET', 'key', '1', '2']
         );
       });
 
       it('Buffer', () => {
         assert.deepEqual(
-          HSET.transformArguments(Buffer.from('key'), Buffer.from('field'), Buffer.from('value')),
+          parseArgs(HSET, Buffer.from('key'), Buffer.from('field'), Buffer.from('value')),
           ['HSET', Buffer.from('key'), Buffer.from('field'), Buffer.from('value')]
         );
       });
@@ -29,14 +30,14 @@ describe('HSET', () => {
 
     it('Map', () => {
       assert.deepEqual(
-        HSET.transformArguments('key', new Map([['field', 'value']])),
+        parseArgs(HSET, 'key', new Map([['field', 'value']])),
         ['HSET', 'key', 'field', 'value']
       );
     });
 
     it('Array', () => {
       assert.deepEqual(
-        HSET.transformArguments('key', [['field', 'value']]),
+        parseArgs(HSET, 'key', [['field', 'value']]),
         ['HSET', 'key', 'field', 'value']
       );
     });
@@ -44,14 +45,14 @@ describe('HSET', () => {
     describe('Object', () => {
       it('string', () => {
         assert.deepEqual(
-          HSET.transformArguments('key', { field: 'value' }),
+          parseArgs(HSET, 'key', { field: 'value' }),
           ['HSET', 'key', 'field', 'value']
         );
       });
 
       it('Buffer', () => {
         assert.deepEqual(
-          HSET.transformArguments('key', { field: Buffer.from('value') }),
+          parseArgs(HSET, 'key', { field: Buffer.from('value') }),
           ['HSET', 'key', 'field', Buffer.from('value')]
         );
       });
diff --git a/packages/client/lib/commands/HSET.ts b/packages/client/lib/commands/HSET.ts
index e14aa9d06f6..db051576750 100644
--- a/packages/client/lib/commands/HSET.ts
+++ b/packages/client/lib/commands/HSET.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type HashTypes = RedisArgument | number;
 
@@ -18,52 +19,58 @@ export type HSETArguments = SingleFieldArguments | MultipleFieldsArguments;
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(...[key, value, fieldValue]: SingleFieldArguments | MultipleFieldsArguments) {
-    const args: Array<RedisArgument> = ['HSET', key];
+  parseCommand(parser: CommandParser, ...[key, value, fieldValue]: SingleFieldArguments | MultipleFieldsArguments) {
+    parser.push('HSET');
+    parser.pushKey(key);
 
     if (typeof value === 'string' || typeof value === 'number' || value instanceof Buffer) {
-      args.push(
-        convertValue(value),
-        convertValue(fieldValue!)
+      parser.pushVariadic(
+        [
+          convertValue(value),
+          convertValue(fieldValue!)
+        ]
       );
     } else if (value instanceof Map) {
-      pushMap(args, value);
+      pushMap(parser, value);
     } else if (Array.isArray(value)) {
-      pushTuples(args, value);
+      pushTuples(parser, value);
     } else {
-      pushObject(args, value);
+      pushObject(parser, value);
     }
-
-    return args;
   },
+  transformArguments(...[key, value, fieldValue]: SingleFieldArguments | MultipleFieldsArguments) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
 
-function pushMap(args: Array<RedisArgument>, map: HSETMap): void {
+function pushMap(parser: CommandParser, map: HSETMap): void {
   for (const [key, value] of map.entries()) {
-    args.push(
-      convertValue(key),
-      convertValue(value)
+    parser.pushVariadic(
+      [
+        convertValue(key),
+        convertValue(value)
+      ]
     );
   }
 }
 
-function pushTuples(args: Array<RedisArgument>, tuples: HSETTuples): void {
+function pushTuples(parser: CommandParser, tuples: HSETTuples): void {
   for (const tuple of tuples) {
     if (Array.isArray(tuple)) {
-      pushTuples(args, tuple);
+      pushTuples(parser, tuple);
       continue;
     }
 
-    args.push(convertValue(tuple));
+    parser.push(convertValue(tuple));
   }
 }
 
-function pushObject(args: Array<RedisArgument>, object: HSETObject): void {
+function pushObject(parser: CommandParser, object: HSETObject): void {
   for (const key of Object.keys(object)) {
-    args.push(
-      convertValue(key),
-      convertValue(object[key])
+    parser.pushVariadic(
+      [
+        convertValue(key),
+        convertValue(object[key])
+      ]
     );
   }
 }
diff --git a/packages/client/lib/commands/HSETNX.spec.ts b/packages/client/lib/commands/HSETNX.spec.ts
index 522732624e1..e65f9fb219c 100644
--- a/packages/client/lib/commands/HSETNX.spec.ts
+++ b/packages/client/lib/commands/HSETNX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HSETNX from './HSETNX';
+import { parseArgs } from './generic-transformers';
 
 describe('HSETNX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HSETNX.transformArguments('key', 'field', 'value'),
+      parseArgs(HSETNX, 'key', 'field', 'value'),
       ['HSETNX', 'key', 'field', 'value']
     );
   });
diff --git a/packages/client/lib/commands/HSETNX.ts b/packages/client/lib/commands/HSETNX.ts
index d26c42a76b4..7d022b52856 100644
--- a/packages/client/lib/commands/HSETNX.ts
+++ b/packages/client/lib/commands/HSETNX.ts
@@ -1,14 +1,23 @@
 import { RedisArgument, Command, NumberReply } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     field: RedisArgument,
     value: RedisArgument
   ) {
-    return ['HSETNX', key, field, value];
+    parser.push('HSETNX');
+    parser.pushKey(key);
+    parser.pushVariadic([field, value]);
   },
+  transformArguments(
+    key: RedisArgument,
+    field: RedisArgument,
+    value: RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply<0 | 1>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HSTRLEN.spec.ts b/packages/client/lib/commands/HSTRLEN.spec.ts
index 59b737b692b..47dd0eaf795 100644
--- a/packages/client/lib/commands/HSTRLEN.spec.ts
+++ b/packages/client/lib/commands/HSTRLEN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HSTRLEN from './HSTRLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('HSTRLEN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      HSTRLEN.transformArguments('key', 'field'),
+      parseArgs(HSTRLEN, 'key', 'field'),
       ['HSTRLEN', 'key', 'field']
     );
   });
diff --git a/packages/client/lib/commands/HSTRLEN.ts b/packages/client/lib/commands/HSTRLEN.ts
index 843c4baf7ef..47bca5d0ced 100644
--- a/packages/client/lib/commands/HSTRLEN.ts
+++ b/packages/client/lib/commands/HSTRLEN.ts
@@ -1,10 +1,15 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, field: RedisArgument) {
-    return ['HSTRLEN', key, field];
+  parseCommand(parser: CommandParser, key: RedisArgument, field: RedisArgument) {
+    parser.setCachable();
+    parser.push('HSTRLEN');
+    parser.pushKey(key);
+    parser.push(field);
   },
+  transformArguments(key: RedisArgument, field: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/HVALS.spec.ts b/packages/client/lib/commands/HVALS.spec.ts
index 922aa588137..89cbb52861c 100644
--- a/packages/client/lib/commands/HVALS.spec.ts
+++ b/packages/client/lib/commands/HVALS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import HVALS from './HVALS';
+import { parseArgs } from './generic-transformers';
 
 describe('HVALS', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      HVALS.transformArguments('key'),
+      parseArgs(HVALS, 'key'),
       ['HVALS', 'key']
     );
   });
diff --git a/packages/client/lib/commands/HVALS.ts b/packages/client/lib/commands/HVALS.ts
index ee4193f5cec..50e0203a3c0 100644
--- a/packages/client/lib/commands/HVALS.ts
+++ b/packages/client/lib/commands/HVALS.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['HVALS', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('HVALS');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/INCR.spec.ts b/packages/client/lib/commands/INCR.spec.ts
index 67129760245..0fe7ed7f8e6 100644
--- a/packages/client/lib/commands/INCR.spec.ts
+++ b/packages/client/lib/commands/INCR.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import INCR from './INCR';
+import { parseArgs } from './generic-transformers';
 
 describe('INCR', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      INCR.transformArguments('key'),
+      parseArgs(INCR, 'key'),
       ['INCR', 'key']
     );
   });
diff --git a/packages/client/lib/commands/INCR.ts b/packages/client/lib/commands/INCR.ts
index eb38256c9dc..0d31b6ef44f 100644
--- a/packages/client/lib/commands/INCR.ts
+++ b/packages/client/lib/commands/INCR.ts
@@ -1,9 +1,12 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument) {
-    return ['INCR', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('INCR');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/INCRBY.spec.ts b/packages/client/lib/commands/INCRBY.spec.ts
index d66c01acce5..e2a5842f20a 100644
--- a/packages/client/lib/commands/INCRBY.spec.ts
+++ b/packages/client/lib/commands/INCRBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import INCRBY from './INCRBY';
+import { parseArgs } from './generic-transformers';
 
 describe('INCRBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      INCRBY.transformArguments('key', 1),
+      parseArgs(INCRBY, 'key', 1),
       ['INCRBY', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/INCRBY.ts b/packages/client/lib/commands/INCRBY.ts
index 5e94348fe63..f909c00416f 100644
--- a/packages/client/lib/commands/INCRBY.ts
+++ b/packages/client/lib/commands/INCRBY.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, increment: number) {
-    return ['INCRBY', key, increment.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, increment: number) {
+    parser.push('INCRBY');
+    parser.pushKey(key);
+    parser.push(increment.toString());
   },
+  transformArguments(key: RedisArgument, increment: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/INCRBYFLOAT.spec.ts b/packages/client/lib/commands/INCRBYFLOAT.spec.ts
index 8bdd9c332de..57596970708 100644
--- a/packages/client/lib/commands/INCRBYFLOAT.spec.ts
+++ b/packages/client/lib/commands/INCRBYFLOAT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import INCRBYFLOAT from './INCRBYFLOAT';
+import { parseArgs } from './generic-transformers';
 
 describe('INCRBYFLOAT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      INCRBYFLOAT.transformArguments('key', 1.5),
+      parseArgs(INCRBYFLOAT, 'key', 1.5),
       ['INCRBYFLOAT', 'key', '1.5']
     );
   });
diff --git a/packages/client/lib/commands/INCRBYFLOAT.ts b/packages/client/lib/commands/INCRBYFLOAT.ts
index 16f59e68c17..9f79cf0c6b0 100644
--- a/packages/client/lib/commands/INCRBYFLOAT.ts
+++ b/packages/client/lib/commands/INCRBYFLOAT.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, increment: number) {
-    return ['INCRBYFLOAT', key, increment.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, increment: number) {
+    parser.push('INCRBYFLOAT');
+    parser.pushKey(key);
+    parser.push(increment.toString());
   },
+  transformArguments(key: RedisArgument, increment: number) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/INFO.spec.ts b/packages/client/lib/commands/INFO.spec.ts
index c4555778729..7ee8a95c137 100644
--- a/packages/client/lib/commands/INFO.spec.ts
+++ b/packages/client/lib/commands/INFO.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import INFO from './INFO';
+import { parseArgs } from './generic-transformers';
 
 describe('INFO', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        INFO.transformArguments(),
+        parseArgs(INFO),
         ['INFO']
       );
     });
 
     it('server section', () => {
       assert.deepEqual(
-        INFO.transformArguments('server'),
+        parseArgs(INFO, 'server'),
         ['INFO', 'server']
       );
     });
diff --git a/packages/client/lib/commands/INFO.ts b/packages/client/lib/commands/INFO.ts
index 9877c0cf66b..b91e0f72c58 100644
--- a/packages/client/lib/commands/INFO.ts
+++ b/packages/client/lib/commands/INFO.ts
@@ -1,16 +1,16 @@
 import { RedisArgument, VerbatimStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(section?: RedisArgument) {
-    const args: Array<RedisArgument> = ['INFO'];
+  parseCommand(parser: CommandParser, section?: RedisArgument) {
+    parser.push('INFO');
 
     if (section) {
-      args.push(section);
+      parser.push(section);
     }
-
-    return args;
   },
+  transformArguments(section?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => VerbatimStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/KEYS.ts b/packages/client/lib/commands/KEYS.ts
index 488ba1154c9..4e5a12f77f1 100644
--- a/packages/client/lib/commands/KEYS.ts
+++ b/packages/client/lib/commands/KEYS.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(pattern: RedisArgument) {
-    return ['KEYS', pattern];
+  parseCommand(parser: CommandParser, pattern: RedisArgument) {
+    parser.pushVariadic(['KEYS', pattern]);
   },
+  transformArguments(pattern: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LASTSAVE.spec.ts b/packages/client/lib/commands/LASTSAVE.spec.ts
index 74cf30705fa..fba26811170 100644
--- a/packages/client/lib/commands/LASTSAVE.spec.ts
+++ b/packages/client/lib/commands/LASTSAVE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LASTSAVE from './LASTSAVE';
+import { parseArgs } from './generic-transformers';
 
 describe('LASTSAVE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LASTSAVE.transformArguments(),
+      parseArgs(LASTSAVE),
       ['LASTSAVE']
     );
   });
diff --git a/packages/client/lib/commands/LASTSAVE.ts b/packages/client/lib/commands/LASTSAVE.ts
index a65161f78b9..686fbc6d93f 100644
--- a/packages/client/lib/commands/LASTSAVE.ts
+++ b/packages/client/lib/commands/LASTSAVE.ts
@@ -1,8 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser) {
+    parser.push('LASTSAVE');
+  },
   transformArguments() {
     return ['LASTSAVE'];
   },
diff --git a/packages/client/lib/commands/LATENCY_DOCTOR.spec.ts b/packages/client/lib/commands/LATENCY_DOCTOR.spec.ts
index 00eabfb4cb3..654751b5b57 100644
--- a/packages/client/lib/commands/LATENCY_DOCTOR.spec.ts
+++ b/packages/client/lib/commands/LATENCY_DOCTOR.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LATENCY_DOCTOR from './LATENCY_DOCTOR';
+import { parseArgs } from './generic-transformers';
 
 describe('LATENCY DOCTOR', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LATENCY_DOCTOR.transformArguments(),
+      parseArgs(LATENCY_DOCTOR),
       ['LATENCY', 'DOCTOR']
     );
   });
diff --git a/packages/client/lib/commands/LATENCY_DOCTOR.ts b/packages/client/lib/commands/LATENCY_DOCTOR.ts
index 96dc6b65702..85c65d83877 100644
--- a/packages/client/lib/commands/LATENCY_DOCTOR.ts
+++ b/packages/client/lib/commands/LATENCY_DOCTOR.ts
@@ -1,8 +1,12 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['LATENCY', 'DOCTOR']);
+  },
   transformArguments() {
     return ['LATENCY', 'DOCTOR'];
   },
diff --git a/packages/client/lib/commands/LATENCY_GRAPH.spec.ts b/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
index 03ad8e2c886..7135dc1c420 100644
--- a/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
+++ b/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LATENCY_GRAPH from './LATENCY_GRAPH';
+import { parseArgs } from './generic-transformers';
 
 describe('LATENCY GRAPH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LATENCY_GRAPH.transformArguments('command'),
+      parseArgs(LATENCY_GRAPH, 'command'),
       [
         'LATENCY',
         'GRAPH',
diff --git a/packages/client/lib/commands/LATENCY_GRAPH.ts b/packages/client/lib/commands/LATENCY_GRAPH.ts
index 7d5f54288b6..763e05f3402 100644
--- a/packages/client/lib/commands/LATENCY_GRAPH.ts
+++ b/packages/client/lib/commands/LATENCY_GRAPH.ts
@@ -1,4 +1,5 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export const LATENCY_EVENTS = {
   ACTIVE_DEFRAG_CYCLE: 'active-defrag-cycle',
@@ -24,8 +25,9 @@ export type LatencyEvent = typeof LATENCY_EVENTS[keyof typeof LATENCY_EVENTS];
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(event: LatencyEvent) {
-    return ['LATENCY', 'GRAPH', event];
+  parseCommand(parser: CommandParser, event: LatencyEvent) {
+    parser.pushVariadic(['LATENCY', 'GRAPH', event]);
   },
+  transformArguments(event: LatencyEvent) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LATENCY_HISTORY.spec.ts b/packages/client/lib/commands/LATENCY_HISTORY.spec.ts
index 509c856e28f..64f94d0d1a3 100644
--- a/packages/client/lib/commands/LATENCY_HISTORY.spec.ts
+++ b/packages/client/lib/commands/LATENCY_HISTORY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LATENCY_HISTORY from './LATENCY_HISTORY';
+import { parseArgs } from './generic-transformers';
 
 describe('LATENCY HISTORY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LATENCY_HISTORY.transformArguments('command'),
+      parseArgs(LATENCY_HISTORY, 'command'),
       ['LATENCY', 'HISTORY', 'command']
     );
   });
diff --git a/packages/client/lib/commands/LATENCY_HISTORY.ts b/packages/client/lib/commands/LATENCY_HISTORY.ts
index df5b1772b2d..9a04c0f88a2 100644
--- a/packages/client/lib/commands/LATENCY_HISTORY.ts
+++ b/packages/client/lib/commands/LATENCY_HISTORY.ts
@@ -1,4 +1,5 @@
 import { ArrayReply, TuplesReply, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type LatencyEventType = (
   'active-defrag-cycle' |
@@ -22,9 +23,10 @@ export type LatencyEventType = (
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(event: LatencyEventType) {
-    return ['LATENCY', 'HISTORY', event];
+  parseCommand(parser: CommandParser, event: LatencyEventType) {
+    parser.pushVariadic(['LATENCY', 'HISTORY', event]);
   },
+  transformArguments(event: LatencyEventType) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<TuplesReply<[
     timestamp: NumberReply,
     latency: NumberReply
diff --git a/packages/client/lib/commands/LATENCY_LATEST.spec.ts b/packages/client/lib/commands/LATENCY_LATEST.spec.ts
index f85a3ccc8bd..2cd2d9a5e06 100644
--- a/packages/client/lib/commands/LATENCY_LATEST.spec.ts
+++ b/packages/client/lib/commands/LATENCY_LATEST.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LATENCY_LATEST from './LATENCY_LATEST';
+import { parseArgs } from './generic-transformers';
 
 describe('LATENCY LATEST', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LATENCY_LATEST.transformArguments(),
+      parseArgs(LATENCY_LATEST),
       ['LATENCY', 'LATEST']
     );
   });
diff --git a/packages/client/lib/commands/LATENCY_LATEST.ts b/packages/client/lib/commands/LATENCY_LATEST.ts
index 29548af30dc..2dc678fdf2f 100644
--- a/packages/client/lib/commands/LATENCY_LATEST.ts
+++ b/packages/client/lib/commands/LATENCY_LATEST.ts
@@ -1,8 +1,12 @@
 import { ArrayReply, BlobStringReply, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['LATENCY', 'LATEST']);
+  },
   transformArguments() {
     return ['LATENCY', 'LATEST'];
   },
diff --git a/packages/client/lib/commands/LCS.spec.ts b/packages/client/lib/commands/LCS.spec.ts
index ff9d63db1b1..aedbb1b34e3 100644
--- a/packages/client/lib/commands/LCS.spec.ts
+++ b/packages/client/lib/commands/LCS.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LCS from './LCS';
+import { parseArgs } from './generic-transformers';
 
 describe('LCS', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LCS.transformArguments('1', '2'),
+      parseArgs(LCS, '1', '2'),
       ['LCS', '1', '2']
     );
   });
diff --git a/packages/client/lib/commands/LCS.ts b/packages/client/lib/commands/LCS.ts
index b798f12aa37..8f9109783ac 100644
--- a/packages/client/lib/commands/LCS.ts
+++ b/packages/client/lib/commands/LCS.ts
@@ -1,13 +1,20 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key1: RedisArgument,
     key2: RedisArgument
   ) {
-    return ['LCS', key1, key2];
+    parser.push('LCS');
+    parser.pushKeys([key1, key2]);
   },
+  transformArguments(
+    key1: RedisArgument,
+    key2: RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LCS_IDX.spec.ts b/packages/client/lib/commands/LCS_IDX.spec.ts
index 2f60a205faa..c4cc6681d85 100644
--- a/packages/client/lib/commands/LCS_IDX.spec.ts
+++ b/packages/client/lib/commands/LCS_IDX.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LCS_IDX from './LCS_IDX';
+import { parseArgs } from './generic-transformers';
 
 describe('LCS IDX', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LCS_IDX.transformArguments('1', '2'),
+      parseArgs(LCS_IDX, '1', '2'),
       ['LCS', '1', '2', 'IDX']
     );
   });
diff --git a/packages/client/lib/commands/LCS_IDX.ts b/packages/client/lib/commands/LCS_IDX.ts
index 0c266fffe1c..20331529efb 100644
--- a/packages/client/lib/commands/LCS_IDX.ts
+++ b/packages/client/lib/commands/LCS_IDX.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesToMapReply, BlobStringReply, ArrayReply, NumberReply, UnwrapReply, Resp2Reply, Command, TuplesReply } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import LCS from './LCS';
 
 export interface LcsIdxOptions {
@@ -25,21 +26,25 @@ export type LcsIdxReply = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: LCS.FIRST_KEY_INDEX,
   IS_READ_ONLY: LCS.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key1: RedisArgument,
     key2: RedisArgument,
     options?: LcsIdxOptions
   ) {
-    const args = LCS.transformArguments(key1, key2);
+    LCS.parseCommand(parser, key1, key2);
 
-    args.push('IDX');
+    parser.push('IDX');
 
     if (options?.MINMATCHLEN) {
-      args.push('MINMATCHLEN', options.MINMATCHLEN.toString());
+      parser.pushVariadic(['MINMATCHLEN', options.MINMATCHLEN.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key1: RedisArgument,
+    key2: RedisArgument,
+    options?: LcsIdxOptions
+  ) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<LcsIdxReply>>) => ({
       matches: reply[1],
diff --git a/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.spec.ts b/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.spec.ts
index 39ba17e8f2c..92ecad4761c 100644
--- a/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.spec.ts
+++ b/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LCS_IDX_WITHMATCHLEN from './LCS_IDX_WITHMATCHLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('LCS IDX WITHMATCHLEN', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LCS_IDX_WITHMATCHLEN.transformArguments('1', '2'),
+      parseArgs(LCS_IDX_WITHMATCHLEN, '1', '2'),
       ['LCS', '1', '2', 'IDX', 'WITHMATCHLEN']
     );
   });
diff --git a/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.ts b/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.ts
index 4e645852035..9eb6d9ed33a 100644
--- a/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.ts
+++ b/packages/client/lib/commands/LCS_IDX_WITHMATCHLEN.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesToMapReply, BlobStringReply, ArrayReply, TuplesReply, NumberReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import LCS_IDX, { LcsIdxOptions, LcsIdxRange } from './LCS_IDX';
 
 export type LcsIdxWithMatchLenMatches = ArrayReply<
@@ -17,15 +18,20 @@ export type LcsIdxWithMatchLenReply = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: LCS_IDX.FIRST_KEY_INDEX,
   IS_READ_ONLY: LCS_IDX.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key1: RedisArgument,
     key2: RedisArgument,
     options?: LcsIdxOptions
   ) {
-    const args = LCS_IDX.transformArguments(key1, key2);
-    args.push('WITHMATCHLEN');
-    return args;
+    LCS_IDX.parseCommand(parser, key1, key2);
+    parser.push('WITHMATCHLEN');
   },
+  transformArguments(
+    key1: RedisArgument,
+    key2: RedisArgument,
+    options?: LcsIdxOptions
+  ) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<LcsIdxWithMatchLenReply>>) => ({
       matches: reply[1],
diff --git a/packages/client/lib/commands/LCS_LEN.spec.ts b/packages/client/lib/commands/LCS_LEN.spec.ts
index 9dc163a68a9..53a2e83c326 100644
--- a/packages/client/lib/commands/LCS_LEN.spec.ts
+++ b/packages/client/lib/commands/LCS_LEN.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LCS_LEN from './LCS_LEN';
+import { parseArgs } from './generic-transformers';
 
 describe('LCS_LEN', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LCS_LEN.transformArguments('1', '2'),
+      parseArgs(LCS_LEN, '1', '2'),
       ['LCS', '1', '2', 'LEN']
     );
   });
diff --git a/packages/client/lib/commands/LCS_LEN.ts b/packages/client/lib/commands/LCS_LEN.ts
index d5d0e77e4d6..c6f87786c2c 100644
--- a/packages/client/lib/commands/LCS_LEN.ts
+++ b/packages/client/lib/commands/LCS_LEN.ts
@@ -1,16 +1,22 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import LCS from './LCS';
 
 export default {
   FIRST_KEY_INDEX: LCS.FIRST_KEY_INDEX,
   IS_READ_ONLY: LCS.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key1: RedisArgument,
     key2: RedisArgument
   ) {
-    const args = LCS.transformArguments(key1, key2);
-    args.push('LEN');
-    return args;
+    LCS.parseCommand(parser, key1, key2);
+    parser.push('LEN');
   },
+
+  transformArguments(
+    key1: RedisArgument,
+    key2: RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LINDEX.spec.ts b/packages/client/lib/commands/LINDEX.spec.ts
index 60346b85f21..41eff474a1a 100644
--- a/packages/client/lib/commands/LINDEX.spec.ts
+++ b/packages/client/lib/commands/LINDEX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LINDEX from './LINDEX';
+import { parseArgs } from './generic-transformers';
 
 describe('LINDEX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LINDEX.transformArguments('key', 0),
+      parseArgs(LINDEX, 'key', 0),
       ['LINDEX', 'key', '0']
     );
   });
diff --git a/packages/client/lib/commands/LINDEX.ts b/packages/client/lib/commands/LINDEX.ts
index 0478bf9dc41..22c79ee880e 100644
--- a/packages/client/lib/commands/LINDEX.ts
+++ b/packages/client/lib/commands/LINDEX.ts
@@ -1,10 +1,15 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, index: number) {
-    return ['LINDEX', key, index.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, index: number) {
+    parser.setCachable();
+    parser.push('LINDEX');
+    parser.pushKey(key);
+    parser.push(index.toString());
   },
+  transformArguments(key: RedisArgument, index: number) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LINSERT.spec.ts b/packages/client/lib/commands/LINSERT.spec.ts
index 6cafa3f5a84..c3c89d56c12 100644
--- a/packages/client/lib/commands/LINSERT.spec.ts
+++ b/packages/client/lib/commands/LINSERT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LINSERT from './LINSERT';
+import { parseArgs } from './generic-transformers';
 
 describe('LINSERT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LINSERT.transformArguments('key', 'BEFORE', 'pivot', 'element'),
+      parseArgs(LINSERT, 'key', 'BEFORE', 'pivot', 'element'),
       ['LINSERT', 'key', 'BEFORE', 'pivot', 'element']
     );
   });
diff --git a/packages/client/lib/commands/LINSERT.ts b/packages/client/lib/commands/LINSERT.ts
index 4bdc77de5a4..9e987eb48d2 100644
--- a/packages/client/lib/commands/LINSERT.ts
+++ b/packages/client/lib/commands/LINSERT.ts
@@ -1,23 +1,27 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type LInsertPosition = 'BEFORE' | 'AFTER';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     position: LInsertPosition,
     pivot: RedisArgument,
     element: RedisArgument
   ) {
-    return [
-      'LINSERT',
-      key,
-      position,
-      pivot,
-      element
-    ];
+    parser.push('LINSERT');
+    parser.pushKey(key);
+    parser.pushVariadic([position, pivot, element]);
   },
+  transformArguments(
+    key: RedisArgument,
+    position: LInsertPosition,
+    pivot: RedisArgument,
+    element: RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LLEN.spec.ts b/packages/client/lib/commands/LLEN.spec.ts
index f6ac9a73cc3..d86078d0b48 100644
--- a/packages/client/lib/commands/LLEN.spec.ts
+++ b/packages/client/lib/commands/LLEN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LLEN from './LLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('LLEN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LLEN.transformArguments('key'),
+      parseArgs(LLEN, 'key'),
       ['LLEN', 'key']
     );
   });
diff --git a/packages/client/lib/commands/LLEN.ts b/packages/client/lib/commands/LLEN.ts
index dda59ddf291..8b0ffc40899 100644
--- a/packages/client/lib/commands/LLEN.ts
+++ b/packages/client/lib/commands/LLEN.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['LLEN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('LLEN');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LMOVE.spec.ts b/packages/client/lib/commands/LMOVE.spec.ts
index 86740aa7b77..bed3ff8eab0 100644
--- a/packages/client/lib/commands/LMOVE.spec.ts
+++ b/packages/client/lib/commands/LMOVE.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LMOVE from './LMOVE';
+import { parseArgs } from './generic-transformers';
 
 describe('LMOVE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LMOVE.transformArguments('source', 'destination', 'LEFT', 'RIGHT'),
+      parseArgs(LMOVE, 'source', 'destination', 'LEFT', 'RIGHT'),
       ['LMOVE', 'source', 'destination', 'LEFT', 'RIGHT']
     );
   });
diff --git a/packages/client/lib/commands/LMOVE.ts b/packages/client/lib/commands/LMOVE.ts
index 95adc71a0ff..c6922b26c29 100644
--- a/packages/client/lib/commands/LMOVE.ts
+++ b/packages/client/lib/commands/LMOVE.ts
@@ -1,22 +1,26 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { ListSide } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     source: RedisArgument,
     destination: RedisArgument,
     sourceSide: ListSide,
     destinationSide: ListSide
   ) {
-    return [
-      'LMOVE',
-      source,
-      destination,
-      sourceSide,
-      destinationSide,
-    ];
+    parser.push('LMOVE');
+    parser.pushKeys([source, destination]);
+    parser.pushVariadic([sourceSide, destinationSide]);
   },
+  transformArguments(
+    source: RedisArgument,
+    destination: RedisArgument,
+    sourceSide: ListSide,
+    destinationSide: ListSide
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LMPOP.spec.ts b/packages/client/lib/commands/LMPOP.spec.ts
index faf39e053ef..bd2cf869e74 100644
--- a/packages/client/lib/commands/LMPOP.spec.ts
+++ b/packages/client/lib/commands/LMPOP.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LMPOP from './LMPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('LMPOP', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('LMPOP', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        LMPOP.transformArguments('key', 'LEFT'),
+        parseArgs(LMPOP, 'key', 'LEFT'),
         ['LMPOP', '1', 'key', 'LEFT']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        LMPOP.transformArguments('key', 'LEFT', {
+        parseArgs(LMPOP, 'key', 'LEFT', {
           COUNT: 2
         }),
         ['LMPOP', '1', 'key', 'LEFT', 'COUNT', '2']
diff --git a/packages/client/lib/commands/LMPOP.ts b/packages/client/lib/commands/LMPOP.ts
index 49f7272ec46..52d6248e0c3 100644
--- a/packages/client/lib/commands/LMPOP.ts
+++ b/packages/client/lib/commands/LMPOP.ts
@@ -1,35 +1,42 @@
-import { CommandArguments, NullReply, TuplesReply, BlobStringReply, Command } from '../RESP/types';
-import { ListSide, RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
+import { NullReply, TuplesReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
+import { ListSide, RedisVariadicArgument } from './generic-transformers';
 
 export interface LMPopOptions {
   COUNT?: number;
 }
 
-export function transformLMPopArguments(
-  args: CommandArguments,
+export function parseLMPopArguments(
+  parser: CommandParser,
   keys: RedisVariadicArgument,
   side: ListSide,
   options?: LMPopOptions
-): CommandArguments {
-  args = pushVariadicArgument(args, keys);
-
-  args.push(side);
+) {
+  parser.pushKeysLength(keys);
+  parser.push(side);
 
   if (options?.COUNT !== undefined) {
-    args.push('COUNT', options.COUNT.toString());
+    parser.pushVariadic(['COUNT', options.COUNT.toString()]);
   }
-
-  return args;
 }
 
-export type LMPopArguments = typeof transformLMPopArguments extends (_: any, ...args: infer T) => any ? T : never;
+function transformArguments(keys: RedisVariadicArgument, side: ListSide, options?: LMPopOptions) { return [] }
+
+export type LMPopArguments = Parameters<typeof transformArguments>;
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(...args: LMPopArguments) {
-    return transformLMPopArguments(['LMPOP'], ...args);
+  parseCommand(
+    parser: CommandParser,
+    keys: RedisVariadicArgument,
+    side: ListSide,
+    options?: LMPopOptions
+  ) {
+    parser.push('LMPOP');
+    parseLMPopArguments(parser, keys, side, options);
   },
+  transformArguments: transformArguments,
   transformReply: undefined as unknown as () => NullReply | TuplesReply<[
     key: BlobStringReply,
     elements: Array<BlobStringReply>
diff --git a/packages/client/lib/commands/LOLWUT.spec.ts b/packages/client/lib/commands/LOLWUT.spec.ts
index b05c4168f6f..b06030b0d0e 100644
--- a/packages/client/lib/commands/LOLWUT.spec.ts
+++ b/packages/client/lib/commands/LOLWUT.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LOLWUT from './LOLWUT';
+import { parseArgs } from './generic-transformers';
 
 describe('LOLWUT', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        LOLWUT.transformArguments(),
+        parseArgs(LOLWUT),
         ['LOLWUT']
       );
     });
 
     it('with version', () => {
       assert.deepEqual(
-        LOLWUT.transformArguments(5),
+        parseArgs(LOLWUT, 5),
         ['LOLWUT', 'VERSION', '5']
       );
     });
 
     it('with version and optional arguments', () => {
       assert.deepEqual(
-        LOLWUT.transformArguments(5, 1, 2, 3),
+        parseArgs(LOLWUT, 5, 1, 2, 3),
         ['LOLWUT', 'VERSION', '5', '1', '2', '3']
       );
     });
diff --git a/packages/client/lib/commands/LOLWUT.ts b/packages/client/lib/commands/LOLWUT.ts
index 7a6c8329d69..413cbc936d8 100644
--- a/packages/client/lib/commands/LOLWUT.ts
+++ b/packages/client/lib/commands/LOLWUT.ts
@@ -1,20 +1,21 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(version?: number, ...optionalArguments: Array<number>) {
-    const args = ['LOLWUT'];
-
+  parseCommand(parser: CommandParser, version?: number, ...optionalArguments: Array<number>) {
+    parser.push('LOLWUT');
     if (version) {
-      args.push(
-        'VERSION',
-        version.toString(),
-        ...optionalArguments.map(String),
+      parser.pushVariadic(
+        [
+          'VERSION',
+          version.toString(),
+          ...optionalArguments.map(String),
+        ]
       );
     }
-
-    return args;
   },
+  transformArguments(version?: number, ...optionalArguments: Array<number>) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPOP.spec.ts b/packages/client/lib/commands/LPOP.spec.ts
index 944e559b15f..93449bdbf5f 100644
--- a/packages/client/lib/commands/LPOP.spec.ts
+++ b/packages/client/lib/commands/LPOP.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPOP from './LPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('LPOP', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LPOP.transformArguments('key'),
+      parseArgs(LPOP, 'key'),
       ['LPOP', 'key']
     );
   });
diff --git a/packages/client/lib/commands/LPOP.ts b/packages/client/lib/commands/LPOP.ts
index 7c85c30f9a1..b2b45fc319c 100644
--- a/packages/client/lib/commands/LPOP.ts
+++ b/packages/client/lib/commands/LPOP.ts
@@ -1,9 +1,12 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument) {
-    return ['LPOP', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('LPOP');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPOP_COUNT.spec.ts b/packages/client/lib/commands/LPOP_COUNT.spec.ts
index 8286a504428..04bb3648d0a 100644
--- a/packages/client/lib/commands/LPOP_COUNT.spec.ts
+++ b/packages/client/lib/commands/LPOP_COUNT.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPOP_COUNT from './LPOP_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('LPOP COUNT', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      LPOP_COUNT.transformArguments('key', 1),
+      parseArgs(LPOP_COUNT, 'key', 1),
       ['LPOP', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/LPOP_COUNT.ts b/packages/client/lib/commands/LPOP_COUNT.ts
index a1536e78dcb..5f0658a0b8a 100644
--- a/packages/client/lib/commands/LPOP_COUNT.ts
+++ b/packages/client/lib/commands/LPOP_COUNT.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NullReply, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['LPOP', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('LPOP');
+    parser.pushKey(key);
+    parser.push(count.toString())
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => NullReply | ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPOS.spec.ts b/packages/client/lib/commands/LPOS.spec.ts
index 94c0bb3c034..f26af3f540f 100644
--- a/packages/client/lib/commands/LPOS.spec.ts
+++ b/packages/client/lib/commands/LPOS.spec.ts
@@ -1,21 +1,22 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPOS from './LPOS';
+import { parseArgs } from './generic-transformers';
 
 describe('LPOS', () => {
   testUtils.isVersionGreaterThanHook([6, 0, 6]);
 
-  describe('transformArguments', () => {
+  describe('processCommand', () => {
     it('simple', () => {
       assert.deepEqual(
-        LPOS.transformArguments('key', 'element'),
+        parseArgs(LPOS, 'key', 'element'),
         ['LPOS', 'key', 'element']
       );
     });
 
     it('with RANK', () => {
       assert.deepEqual(
-        LPOS.transformArguments('key', 'element', {
+        parseArgs(LPOS, 'key', 'element', {
           RANK: 0
         }),
         ['LPOS', 'key', 'element', 'RANK', '0']
@@ -24,7 +25,7 @@ describe('LPOS', () => {
 
     it('with MAXLEN', () => {
       assert.deepEqual(
-        LPOS.transformArguments('key', 'element', {
+        parseArgs(LPOS, 'key', 'element', {
           MAXLEN: 10
         }),
         ['LPOS', 'key', 'element', 'MAXLEN', '10']
@@ -33,7 +34,7 @@ describe('LPOS', () => {
 
     it('with RANK, MAXLEN', () => {
       assert.deepEqual(
-        LPOS.transformArguments('key', 'element', {
+        parseArgs(LPOS, 'key', 'element', {
           RANK: 0,
           MAXLEN: 10
         }),
diff --git a/packages/client/lib/commands/LPOS.ts b/packages/client/lib/commands/LPOS.ts
index 047d80d7c29..2a98ee21dc7 100644
--- a/packages/client/lib/commands/LPOS.ts
+++ b/packages/client/lib/commands/LPOS.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface LPosOptions {
   RANK?: number;
@@ -8,24 +9,31 @@ export interface LPosOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     element: RedisArgument,
     options?: LPosOptions
   ) {
-    const args = ['LPOS', key, element];
+    parser.setCachable();
+    parser.push('LPOS');
+    parser.pushKey(key);
+    parser.push(element);
 
     if (options) {
       if (typeof options.RANK === 'number') {
-        args.push('RANK', options.RANK.toString());
+        parser.pushVariadic(['RANK', options.RANK.toString()]);
       }
 
       if (typeof options.MAXLEN === 'number') {
-        args.push('MAXLEN', options.MAXLEN.toString());
+        parser.pushVariadic(['MAXLEN', options.MAXLEN.toString()]);
       }
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    element: RedisArgument,
+    options?: LPosOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPOS_COUNT.spec.ts b/packages/client/lib/commands/LPOS_COUNT.spec.ts
index 747ffbc01cf..d881374c2f7 100644
--- a/packages/client/lib/commands/LPOS_COUNT.spec.ts
+++ b/packages/client/lib/commands/LPOS_COUNT.spec.ts
@@ -1,21 +1,22 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPOS_COUNT from './LPOS_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('LPOS COUNT', () => {
   testUtils.isVersionGreaterThanHook([6, 0, 6]);
 
-  describe('transformArguments', () => {
+  describe('processCommand', () => {
     it('simple', () => {
       assert.deepEqual(
-        LPOS_COUNT.transformArguments('key', 'element', 0),
+        parseArgs(LPOS_COUNT, 'key', 'element', 0),
         ['LPOS', 'key', 'element', 'COUNT', '0']
       );
     });
 
     it('with RANK', () => {
       assert.deepEqual(
-        LPOS_COUNT.transformArguments('key', 'element', 0, {
+        parseArgs(LPOS_COUNT, 'key', 'element', 0, {
           RANK: 0
         }),
         ['LPOS', 'key', 'element', 'RANK', '0', 'COUNT', '0']
@@ -24,7 +25,7 @@ describe('LPOS COUNT', () => {
 
     it('with MAXLEN', () => {
       assert.deepEqual(
-        LPOS_COUNT.transformArguments('key', 'element', 0, {
+        parseArgs(LPOS_COUNT, 'key', 'element', 0, {
           MAXLEN: 10
         }),
         ['LPOS', 'key', 'element', 'COUNT', '0', 'MAXLEN', '10']
@@ -33,7 +34,7 @@ describe('LPOS COUNT', () => {
 
     it('with RANK, MAXLEN', () => {
       assert.deepEqual(
-        LPOS_COUNT.transformArguments('key', 'element', 0, {
+        parseArgs(LPOS_COUNT, 'key', 'element', 0, {
           RANK: 0,
           MAXLEN: 10
         }),
diff --git a/packages/client/lib/commands/LPOS_COUNT.ts b/packages/client/lib/commands/LPOS_COUNT.ts
index 1b057cff1f6..209ea6f000c 100644
--- a/packages/client/lib/commands/LPOS_COUNT.ts
+++ b/packages/client/lib/commands/LPOS_COUNT.ts
@@ -1,28 +1,37 @@
 import { RedisArgument, ArrayReply, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import LPOS, { LPosOptions } from './LPOS';
 
 export default {
   FIRST_KEY_INDEX: LPOS.FIRST_KEY_INDEX,
   IS_READ_ONLY: LPOS.IS_READ_ONLY,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     element: RedisArgument,
     count: number,
     options?: LPosOptions
   ) {
-    const args = ['LPOS', key, element];
+    parser.setCachable();
+    parser.push('LPOS');
+    parser.pushKey(key);
+    parser.push(element);
 
     if (options?.RANK !== undefined) {
-      args.push('RANK', options.RANK.toString());
-    }
-
-    args.push('COUNT', count.toString());
+        parser.pushVariadic(['RANK', options.RANK.toString()]);
+      }
 
-    if (options?.MAXLEN !== undefined) {
-      args.push('MAXLEN', options.MAXLEN.toString());
-    }
+      parser.pushVariadic(['COUNT', count.toString()]);
 
-    return args;
+      if (options?.MAXLEN !== undefined) {
+        parser.pushVariadic(['MAXLEN', options.MAXLEN.toString()]);
+      }
   },
+  transformArguments(
+    key: RedisArgument,
+    element: RedisArgument,
+    count: number,
+    options?: LPosOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<NumberReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPUSH.spec.ts b/packages/client/lib/commands/LPUSH.spec.ts
index 8d2ddb5ccc2..09c7d9da772 100644
--- a/packages/client/lib/commands/LPUSH.spec.ts
+++ b/packages/client/lib/commands/LPUSH.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPUSH from './LPUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('LPUSH', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        LPUSH.transformArguments('key', 'field'),
+        parseArgs(LPUSH, 'key', 'field'),
         ['LPUSH', 'key', 'field']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        LPUSH.transformArguments('key', ['1', '2']),
+        parseArgs(LPUSH, 'key', ['1', '2']),
         ['LPUSH', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/LPUSH.ts b/packages/client/lib/commands/LPUSH.ts
index 714db2ae9a9..fd9da3b7866 100644
--- a/packages/client/lib/commands/LPUSH.ts
+++ b/packages/client/lib/commands/LPUSH.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, elements: RedisVariadicArgument) {
-    return pushVariadicArguments(['LPUSH', key], elements);
+  parseCommand(parser: CommandParser, key: RedisArgument, elements: RedisVariadicArgument) {
+    parser.push('LPUSH');
+    parser.pushKey(key);
+    parser.pushVariadic(elements);
   },
+  transformArguments(key: RedisArgument, elements: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LPUSHX.spec.ts b/packages/client/lib/commands/LPUSHX.spec.ts
index f7dafe025c7..179a0ddb29e 100644
--- a/packages/client/lib/commands/LPUSHX.spec.ts
+++ b/packages/client/lib/commands/LPUSHX.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LPUSHX from './LPUSHX';
+import { parseArgs } from './generic-transformers';
 
 describe('LPUSHX', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        LPUSHX.transformArguments('key', 'element'),
+        parseArgs(LPUSHX, 'key', 'element'),
         ['LPUSHX', 'key', 'element']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        LPUSHX.transformArguments('key', ['1', '2']),
+        parseArgs(LPUSHX, 'key', ['1', '2']),
         ['LPUSHX', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/LPUSHX.ts b/packages/client/lib/commands/LPUSHX.ts
index d6dceda6d02..6afe6e4083b 100644
--- a/packages/client/lib/commands/LPUSHX.ts
+++ b/packages/client/lib/commands/LPUSHX.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, elements: RedisVariadicArgument) {
-    return pushVariadicArguments(['LPUSHX', key], elements);
+  parseCommand(parser: CommandParser, key: RedisArgument, elements: RedisVariadicArgument) {
+    parser.push('LPUSHX');
+    parser.pushKey(key);
+    parser.pushVariadic(elements);
   },
+  transformArguments(key: RedisArgument, elements: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LRANGE.spec.ts b/packages/client/lib/commands/LRANGE.spec.ts
index 3e768cc0731..c0bb046d898 100644
--- a/packages/client/lib/commands/LRANGE.spec.ts
+++ b/packages/client/lib/commands/LRANGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LRANGE from './LRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('LRANGE', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      LRANGE.transformArguments('key', 0, -1),
+      parseArgs(LRANGE, 'key', 0, -1),
       ['LRANGE', 'key', '0', '-1']
     );
   });
diff --git a/packages/client/lib/commands/LRANGE.ts b/packages/client/lib/commands/LRANGE.ts
index 4b4b3488baa..1badfe92ca8 100644
--- a/packages/client/lib/commands/LRANGE.ts
+++ b/packages/client/lib/commands/LRANGE.ts
@@ -1,19 +1,15 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    start: number,
-    stop: number
-) {
-    return [
-      'LRANGE',
-      key,
-      start.toString(),
-      stop.toString()
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, start: number, stop: number) {
+    parser.setCachable();
+    parser.push('LRANGE');
+    parser.pushKey(key);
+    parser.pushVariadic([start.toString(), stop.toString()])
   },
+  transformArguments(key: RedisArgument, start: number, stop: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LREM.spec.ts b/packages/client/lib/commands/LREM.spec.ts
index 1a35dab7c54..2a36d8ee2f1 100644
--- a/packages/client/lib/commands/LREM.spec.ts
+++ b/packages/client/lib/commands/LREM.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LREM from './LREM';
+import { parseArgs } from './generic-transformers';
 
 describe('LREM', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LREM.transformArguments('key', 0, 'element'),
+      parseArgs(LREM, 'key', 0, 'element'),
       ['LREM', 'key', '0', 'element']
     );
   });
diff --git a/packages/client/lib/commands/LREM.ts b/packages/client/lib/commands/LREM.ts
index dbd2002be8b..ce6750ab325 100644
--- a/packages/client/lib/commands/LREM.ts
+++ b/packages/client/lib/commands/LREM.ts
@@ -1,19 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    count: number,
-    element: RedisArgument
-  ) {
-    return [
-      'LREM',
-      key,
-      count.toString(),
-      element
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number, element: RedisArgument) {
+    parser.push('LREM');
+    parser.pushKey(key);
+    parser.push(count.toString());
+    parser.push(element);
   },
+  transformArguments(key: RedisArgument, count: number, element: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LSET.spec.ts b/packages/client/lib/commands/LSET.spec.ts
index ae4b1bf9f2f..c7522942402 100644
--- a/packages/client/lib/commands/LSET.spec.ts
+++ b/packages/client/lib/commands/LSET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LSET from './LSET';
+import { parseArgs } from './generic-transformers';
 
 describe('LSET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LSET.transformArguments('key', 0, 'element'),
+      parseArgs(LSET, 'key', 0, 'element'),
       ['LSET', 'key', '0', 'element']
     );
   });
diff --git a/packages/client/lib/commands/LSET.ts b/packages/client/lib/commands/LSET.ts
index edb86baae0f..8fc0f52e92f 100644
--- a/packages/client/lib/commands/LSET.ts
+++ b/packages/client/lib/commands/LSET.ts
@@ -1,19 +1,14 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    index: number,
-    element: RedisArgument
-  ) {
-    return [
-      'LSET',
-      key,
-      index.toString(),
-      element
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, index: number, element: RedisArgument) {
+    parser.push('LSET');
+    parser.pushKey(key);
+    parser.pushVariadic([index.toString(), element]);
   },
+  transformArguments(key: RedisArgument, index: number, element: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/LTRIM.spec.ts b/packages/client/lib/commands/LTRIM.spec.ts
index 3edc3669737..5b6d77c91de 100644
--- a/packages/client/lib/commands/LTRIM.spec.ts
+++ b/packages/client/lib/commands/LTRIM.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LTRIM from './LTRIM';
+import { parseArgs } from './generic-transformers';
 
 describe('LTRIM', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LTRIM.transformArguments('key', 0, -1),
+      parseArgs(LTRIM, 'key', 0, -1),
       ['LTRIM', 'key', '0', '-1']
     );
   });
diff --git a/packages/client/lib/commands/LTRIM.ts b/packages/client/lib/commands/LTRIM.ts
index b80aa6264e9..2ab4851c1fe 100644
--- a/packages/client/lib/commands/LTRIM.ts
+++ b/packages/client/lib/commands/LTRIM.ts
@@ -1,18 +1,13 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    start: number,
-    stop: number
-  ) {
-    return [
-      'LTRIM',
-      key,
-      start.toString(),
-      stop.toString()
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, start: number, stop: number) {
+    parser.push('LTRIM');
+    parser.pushKey(key);
+    parser.pushVariadic([start.toString(), stop.toString()]);
   },
+  transformArguments(key: RedisArgument, start: number, stop: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MEMORY_DOCTOR.spec.ts b/packages/client/lib/commands/MEMORY_DOCTOR.spec.ts
index e1d718d7aab..9d822f8e07e 100644
--- a/packages/client/lib/commands/MEMORY_DOCTOR.spec.ts
+++ b/packages/client/lib/commands/MEMORY_DOCTOR.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MEMORY_DOCTOR from './MEMORY_DOCTOR';
+import { parseArgs } from './generic-transformers';
 
 describe('MEMORY DOCTOR', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MEMORY_DOCTOR.transformArguments(),
+      parseArgs(MEMORY_DOCTOR),
       ['MEMORY', 'DOCTOR']
     );
   });
diff --git a/packages/client/lib/commands/MEMORY_DOCTOR.ts b/packages/client/lib/commands/MEMORY_DOCTOR.ts
index 6f8eb29ef2b..bc1f5fe9754 100644
--- a/packages/client/lib/commands/MEMORY_DOCTOR.ts
+++ b/packages/client/lib/commands/MEMORY_DOCTOR.ts
@@ -1,10 +1,12 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['MEMORY', 'DOCTOR'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['MEMORY', 'DOCTOR']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MEMORY_MALLOC-STATS.spec.ts b/packages/client/lib/commands/MEMORY_MALLOC-STATS.spec.ts
index 8484fcbf0b7..a4a85f5b994 100644
--- a/packages/client/lib/commands/MEMORY_MALLOC-STATS.spec.ts
+++ b/packages/client/lib/commands/MEMORY_MALLOC-STATS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MEMORY_MALLOC_STATS from './MEMORY_MALLOC-STATS';
+import { parseArgs } from './generic-transformers';
 
 describe('MEMORY MALLOC-STATS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MEMORY_MALLOC_STATS.transformArguments(),
+      parseArgs(MEMORY_MALLOC_STATS),
       ['MEMORY', 'MALLOC-STATS']
     );
   });
diff --git a/packages/client/lib/commands/MEMORY_MALLOC-STATS.ts b/packages/client/lib/commands/MEMORY_MALLOC-STATS.ts
index 31b01a49b5c..258f17d93b6 100644
--- a/packages/client/lib/commands/MEMORY_MALLOC-STATS.ts
+++ b/packages/client/lib/commands/MEMORY_MALLOC-STATS.ts
@@ -1,11 +1,13 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['MEMORY', 'MALLOC-STATS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['MEMORY', 'MALLOC-STATS']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/MEMORY_PURGE.spec.ts b/packages/client/lib/commands/MEMORY_PURGE.spec.ts
index 41b01f87c4b..be5fb738b0a 100644
--- a/packages/client/lib/commands/MEMORY_PURGE.spec.ts
+++ b/packages/client/lib/commands/MEMORY_PURGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MEMORY_PURGE from './MEMORY_PURGE';
+import { parseArgs } from './generic-transformers';
 
 describe('MEMORY PURGE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MEMORY_PURGE.transformArguments(),
+      parseArgs(MEMORY_PURGE),
       ['MEMORY', 'PURGE']
     );
   });
diff --git a/packages/client/lib/commands/MEMORY_PURGE.ts b/packages/client/lib/commands/MEMORY_PURGE.ts
index b4c48d40102..5b811dec1c9 100644
--- a/packages/client/lib/commands/MEMORY_PURGE.ts
+++ b/packages/client/lib/commands/MEMORY_PURGE.ts
@@ -1,11 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments() {
-    return ['MEMORY', 'PURGE'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['MEMORY', 'PURGE']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/MEMORY_STATS.spec.ts b/packages/client/lib/commands/MEMORY_STATS.spec.ts
index 4fc823c3e66..4d563396ccd 100644
--- a/packages/client/lib/commands/MEMORY_STATS.spec.ts
+++ b/packages/client/lib/commands/MEMORY_STATS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MEMORY_STATS from './MEMORY_STATS';
+import { parseArgs } from './generic-transformers';
 
 describe('MEMORY STATS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MEMORY_STATS.transformArguments(),
+      parseArgs(MEMORY_STATS),
       ['MEMORY', 'STATS']
     );
   });
diff --git a/packages/client/lib/commands/MEMORY_STATS.ts b/packages/client/lib/commands/MEMORY_STATS.ts
index 2192d619ee6..e48b2a70217 100644
--- a/packages/client/lib/commands/MEMORY_STATS.ts
+++ b/packages/client/lib/commands/MEMORY_STATS.ts
@@ -1,4 +1,5 @@
 import { TuplesToMapReply, BlobStringReply, NumberReply, DoubleReply, ArrayReply, UnwrapReply, Command } from '../RESP/types'; 
+import { CommandParser } from '../client/parser';
 
 export type MemoryStatsReply = TuplesToMapReply<[
   [BlobStringReply<'peak.allocated'>, NumberReply],
@@ -35,9 +36,10 @@ export type MemoryStatsReply = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['MEMORY', 'STATS'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['MEMORY', 'STATS']);
   },
+  transformArguments() { return [] },
   transformReply: {
     2: (rawReply: UnwrapReply<ArrayReply<BlobStringReply | NumberReply>>) => {
       const reply: any = {};
diff --git a/packages/client/lib/commands/MEMORY_USAGE.spec.ts b/packages/client/lib/commands/MEMORY_USAGE.spec.ts
index 250a6884259..edf673564ee 100644
--- a/packages/client/lib/commands/MEMORY_USAGE.spec.ts
+++ b/packages/client/lib/commands/MEMORY_USAGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MEMORY_USAGE from './MEMORY_USAGE';
+import { parseArgs } from './generic-transformers';
 
 describe('MEMORY USAGE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        MEMORY_USAGE.transformArguments('key'),
+        parseArgs(MEMORY_USAGE, 'key'),
         ['MEMORY', 'USAGE', 'key']
       );
     });
 
     it('with SAMPLES', () => {
       assert.deepEqual(
-        MEMORY_USAGE.transformArguments('key', {
+        parseArgs(MEMORY_USAGE, 'key', {
           SAMPLES: 1
         }),
         ['MEMORY', 'USAGE', 'key', 'SAMPLES', '1']
diff --git a/packages/client/lib/commands/MEMORY_USAGE.ts b/packages/client/lib/commands/MEMORY_USAGE.ts
index 78b079c2c13..b91184b5723 100644
--- a/packages/client/lib/commands/MEMORY_USAGE.ts
+++ b/packages/client/lib/commands/MEMORY_USAGE.ts
@@ -1,4 +1,5 @@
 import { NumberReply, NullReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface MemoryUsageOptions {
   SAMPLES?: number;
@@ -7,14 +8,14 @@ export interface MemoryUsageOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options?: MemoryUsageOptions) {
-    const args = ['MEMORY', 'USAGE', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: MemoryUsageOptions) {
+    parser.pushVariadic(['MEMORY', 'USAGE']);
+    parser.pushKey(key);
 
     if (options?.SAMPLES) {
-      args.push('SAMPLES', options.SAMPLES.toString());
+      parser.pushVariadic(['SAMPLES', options.SAMPLES.toString()]);
     }
-    
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: MemoryUsageOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MGET.spec.ts b/packages/client/lib/commands/MGET.spec.ts
index 296702a1a03..048fa6f0a58 100644
--- a/packages/client/lib/commands/MGET.spec.ts
+++ b/packages/client/lib/commands/MGET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MGET from './MGET';
+import { parseArgs } from './generic-transformers';
 
 describe('MGET', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      MGET.transformArguments(['1', '2']),
+      parseArgs(MGET, ['1', '2']),
       ['MGET', '1', '2']
     );
   });
diff --git a/packages/client/lib/commands/MGET.ts b/packages/client/lib/commands/MGET.ts
index 0f0f9e52ffb..d805a4ffe73 100644
--- a/packages/client/lib/commands/MGET.ts
+++ b/packages/client/lib/commands/MGET.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: Array<RedisArgument>) {
-    return ['MGET', ...keys];
+  parseCommand(parser: CommandParser, keys: Array<RedisArgument>) {
+    parser.setCachable();
+    parser.push('MGET');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: Array<RedisArgument>) { return [] },
   transformReply: undefined as unknown as () => Array<BlobStringReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MIGRATE.spec.ts b/packages/client/lib/commands/MIGRATE.spec.ts
index 880d59a09c7..dd2fbdc82ff 100644
--- a/packages/client/lib/commands/MIGRATE.spec.ts
+++ b/packages/client/lib/commands/MIGRATE.spec.ts
@@ -1,25 +1,26 @@
 import { strict as assert } from 'node:assert';
 import MIGRATE from './MIGRATE';
+import { parseArgs } from './generic-transformers';
 
 describe('MIGRATE', () => {
   describe('transformArguments', () => {
     it('single key', () => {
       assert.deepEqual(
-        MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10),
+        parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10),
         ['MIGRATE', '127.0.0.1', '6379', 'key', '0', '10']
       );
     });
 
     it('multiple keys', () => {
       assert.deepEqual(
-        MIGRATE.transformArguments('127.0.0.1', 6379, ['1', '2'], 0, 10),
+        parseArgs(MIGRATE, '127.0.0.1', 6379, ['1', '2'], 0, 10),
         ['MIGRATE', '127.0.0.1', '6379', '', '0', '10', 'KEYS', '1', '2']
       );
     });
 
     it('with COPY', () => {
       assert.deepEqual(
-        MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10, {
+        parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10, {
           COPY: true
         }),
         ['MIGRATE', '127.0.0.1', '6379', 'key', '0', '10', 'COPY']
@@ -28,7 +29,7 @@ describe('MIGRATE', () => {
 
     it('with REPLACE', () => {
       assert.deepEqual(
-        MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10, {
+        parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10, {
           REPLACE: true
         }),
         ['MIGRATE', '127.0.0.1', '6379', 'key', '0', '10', 'REPLACE']
@@ -38,7 +39,7 @@ describe('MIGRATE', () => {
     describe('with AUTH', () => {
       it('password only', () => {
         assert.deepEqual(
-          MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10, {
+          parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10, {
             AUTH: {
               password: 'password'
             }
@@ -49,7 +50,7 @@ describe('MIGRATE', () => {
 
       it('username & password', () => {
         assert.deepEqual(
-          MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10, {
+          parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10, {
             AUTH: {
               username: 'username',
               password: 'password'
@@ -62,7 +63,7 @@ describe('MIGRATE', () => {
 
     it('with COPY, REPLACE, AUTH', () => {
       assert.deepEqual(
-        MIGRATE.transformArguments('127.0.0.1', 6379, 'key', 0, 10, {
+        parseArgs(MIGRATE, '127.0.0.1', 6379, 'key', 0, 10, {
           COPY: true,
           REPLACE: true,
           AUTH: {
diff --git a/packages/client/lib/commands/MIGRATE.ts b/packages/client/lib/commands/MIGRATE.ts
index 4821f93fcfb..ab99b3e1324 100644
--- a/packages/client/lib/commands/MIGRATE.ts
+++ b/packages/client/lib/commands/MIGRATE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { AuthOptions } from './AUTH';
 
 export interface MigrateOptions {
@@ -9,7 +10,8 @@ export interface MigrateOptions {
 
 export default {
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     host: RedisArgument,
     port: number,
     key: RedisArgument | Array<RedisArgument>,
@@ -17,51 +19,65 @@ export default {
     timeout: number,
     options?: MigrateOptions
   ) {
-    const args = ['MIGRATE', host, port.toString()],
-      isKeyArray = Array.isArray(key);
+    parser.pushVariadic(['MIGRATE', host, port.toString()]);
+    const isKeyArray = Array.isArray(key);
   
     if (isKeyArray) {
-      args.push('');
+      parser.push('');
     } else {
-      args.push(key);
+      parser.push(key);
     }
   
-    args.push(
-      destinationDb.toString(),
-      timeout.toString()
+    parser.pushVariadic(
+      [
+        destinationDb.toString(),
+        timeout.toString()
+      ]
     );
   
     if (options?.COPY) {
-      args.push('COPY');
+      parser.push('COPY');
     }
   
     if (options?.REPLACE) {
-      args.push('REPLACE');
+      parser.push('REPLACE');
     }
   
     if (options?.AUTH) {
       if (options.AUTH.username) {
-        args.push(
-          'AUTH2',
-          options.AUTH.username,
-          options.AUTH.password
+        parser.pushVariadic(
+          [
+            'AUTH2',
+            options.AUTH.username,
+            options.AUTH.password
+          ]
         );
       } else {
-        args.push(
-          'AUTH',
-          options.AUTH.password
+        parser.pushVariadic(
+          [
+            'AUTH',
+            options.AUTH.password
+          ]
         );
       }
     }
   
     if (isKeyArray) {
-      args.push(
-        'KEYS',
-        ...key
+      parser.pushVariadic(
+        [
+          'KEYS',
+          ...key
+        ]
       );
     }
-  
-    return args;
   },
+  transformArguments(
+    host: RedisArgument,
+    port: number,
+    key: RedisArgument | Array<RedisArgument>,
+    destinationDb: number,
+    timeout: number,
+    options?: MigrateOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MODULE_LIST.spec.ts b/packages/client/lib/commands/MODULE_LIST.spec.ts
index 9c1d3874381..0aab973cf21 100644
--- a/packages/client/lib/commands/MODULE_LIST.spec.ts
+++ b/packages/client/lib/commands/MODULE_LIST.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import MODULE_LIST from './MODULE_LIST';
+import { parseArgs } from './generic-transformers';
 
 describe('MODULE LIST', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MODULE_LIST.transformArguments(),
+      parseArgs(MODULE_LIST),
       ['MODULE', 'LIST']
     );
   });
diff --git a/packages/client/lib/commands/MODULE_LIST.ts b/packages/client/lib/commands/MODULE_LIST.ts
index 5ddd4e91ff6..2395e24122c 100644
--- a/packages/client/lib/commands/MODULE_LIST.ts
+++ b/packages/client/lib/commands/MODULE_LIST.ts
@@ -1,4 +1,5 @@
 import { ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type ModuleListReply = ArrayReply<TuplesToMapReply<[
   [BlobStringReply<'name'>, BlobStringReply],
@@ -8,9 +9,10 @@ export type ModuleListReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['MODULE', 'LIST'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['MODULE', 'LIST']);
   },
+  transformArguments() { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<ModuleListReply>>) => {
       return reply.map(module => {
diff --git a/packages/client/lib/commands/MODULE_LOAD.spec.ts b/packages/client/lib/commands/MODULE_LOAD.spec.ts
index 3b7b9dd00a3..418dd9b5daf 100644
--- a/packages/client/lib/commands/MODULE_LOAD.spec.ts
+++ b/packages/client/lib/commands/MODULE_LOAD.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import MODULE_LOAD from './MODULE_LOAD';
+import { parseArgs } from './generic-transformers';
 
 describe('MODULE LOAD', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        MODULE_LOAD.transformArguments('path'),
+        parseArgs(MODULE_LOAD, 'path'),
         ['MODULE', 'LOAD', 'path']
       );
     });
 
     it('with module args', () => {
       assert.deepEqual(
-        MODULE_LOAD.transformArguments('path', ['1', '2']),
+        parseArgs(MODULE_LOAD, 'path', ['1', '2']),
         ['MODULE', 'LOAD', 'path', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/MODULE_LOAD.ts b/packages/client/lib/commands/MODULE_LOAD.ts
index 82c5b81a905..9fb0faa284b 100644
--- a/packages/client/lib/commands/MODULE_LOAD.ts
+++ b/packages/client/lib/commands/MODULE_LOAD.ts
@@ -1,16 +1,16 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(path: RedisArgument, moduleArguments?: Array<RedisArgument>) {
-    const args = ['MODULE', 'LOAD', path];
+  parseCommand(parser: CommandParser, path: RedisArgument, moduleArguments?: Array<RedisArgument>) {
+    parser.pushVariadic(['MODULE', 'LOAD', path]);
 
     if (moduleArguments) {
-      return args.concat(moduleArguments);
+      parser.pushVariadic(moduleArguments);
     }
-    
-    return args;
   },
+  transformArguments(path: RedisArgument, moduleArguments?: Array<RedisArgument>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MODULE_UNLOAD.spec.ts b/packages/client/lib/commands/MODULE_UNLOAD.spec.ts
index e33fb3a5f4f..581f41e03c8 100644
--- a/packages/client/lib/commands/MODULE_UNLOAD.spec.ts
+++ b/packages/client/lib/commands/MODULE_UNLOAD.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import MODULE_UNLOAD from './MODULE_UNLOAD';
+import { parseArgs } from './generic-transformers';
 
 describe('MODULE UNLOAD', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MODULE_UNLOAD.transformArguments('name'),
+      parseArgs(MODULE_UNLOAD, 'name'),
       ['MODULE', 'UNLOAD', 'name']
     );
   });
diff --git a/packages/client/lib/commands/MODULE_UNLOAD.ts b/packages/client/lib/commands/MODULE_UNLOAD.ts
index 3a2bc05c0e7..607efdc65d9 100644
--- a/packages/client/lib/commands/MODULE_UNLOAD.ts
+++ b/packages/client/lib/commands/MODULE_UNLOAD.ts
@@ -1,10 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(name: RedisArgument) {
-    return ['MODULE', 'UNLOAD', name];
+  parseCommand(parser: CommandParser, name: RedisArgument) {
+    parser.pushVariadic(['MODULE', 'UNLOAD', name]);
   },
+  transformArguments(name: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MOVE.spec.ts b/packages/client/lib/commands/MOVE.spec.ts
index e767568e72b..91a01378b22 100644
--- a/packages/client/lib/commands/MOVE.spec.ts
+++ b/packages/client/lib/commands/MOVE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MOVE from './MOVE';
+import { parseArgs } from './generic-transformers';
 
 describe('MOVE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MOVE.transformArguments('key', 1),
+      parseArgs(MOVE, 'key', 1),
       ['MOVE', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/MOVE.ts b/packages/client/lib/commands/MOVE.ts
index 60aac4b1457..270e81826eb 100644
--- a/packages/client/lib/commands/MOVE.ts
+++ b/packages/client/lib/commands/MOVE.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, db: number) {
-    return ['MOVE', key, db.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, db: number) {
+    parser.push('MOVE');
+    parser.pushKey(key);
+    parser.push(db.toString());
   },
+  transformArguments(key: RedisArgument, db: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MSET.spec.ts b/packages/client/lib/commands/MSET.spec.ts
index 5435e283108..cfb14eceb05 100644
--- a/packages/client/lib/commands/MSET.spec.ts
+++ b/packages/client/lib/commands/MSET.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MSET from './MSET';
+import { parseArgs } from './generic-transformers';
 
 describe('MSET', () => {
   describe('transformArguments', () => {
     it("['key1', 'value1', 'key2', 'value2']", () => {
       assert.deepEqual(
-        MSET.transformArguments(['key1', 'value1', 'key2', 'value2']),
+        parseArgs(MSET, ['key1', 'value1', 'key2', 'value2']),
         ['MSET', 'key1', 'value1', 'key2', 'value2']
       );
     });
 
     it("[['key1', 'value1'], ['key2', 'value2']]", () => {
       assert.deepEqual(
-        MSET.transformArguments([['key1', 'value1'], ['key2', 'value2']]),
+        parseArgs(MSET, [['key1', 'value1'], ['key2', 'value2']]),
         ['MSET', 'key1', 'value1', 'key2', 'value2']
       );
     });
 
     it("{key1: 'value1'. key2: 'value2'}", () => {
       assert.deepEqual(
-        MSET.transformArguments({ key1: 'value1', key2: 'value2' }),
+        parseArgs(MSET, { key1: 'value1', key2: 'value2' }),
         ['MSET', 'key1', 'value1', 'key2', 'value2']
       );
     });
diff --git a/packages/client/lib/commands/MSET.ts b/packages/client/lib/commands/MSET.ts
index 136fde3e7f7..5cef149ca4e 100644
--- a/packages/client/lib/commands/MSET.ts
+++ b/packages/client/lib/commands/MSET.ts
@@ -1,27 +1,43 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type MSetArguments =
   Array<[RedisArgument, RedisArgument]> |
   Array<RedisArgument> |
   Record<string, RedisArgument>;
 
-export function mSetArguments(command: string, toSet: MSetArguments) {
-  const args: Array<RedisArgument> = [command];
+export function mSetArguments(command: string, toSet: MSetArguments) { return [] }
 
+export function parseMSetArguments(command: string, parser: CommandParser, toSet: MSetArguments) {
+  parser.push(command);
   if (Array.isArray(toSet)) {
-    args.push(...toSet.flat());
+    if (toSet.length == 0) {
+      throw new Error("empty toSet Argument")
+    }
+    if (Array.isArray(toSet[0])) {
+      for (const tuple of (toSet as Array<[RedisArgument, RedisArgument]>)) {
+        parser.pushKey(tuple[0]);
+        parser.push(tuple[1]);
+      }
+    } else {
+      const arr = toSet as Array<RedisArgument>;
+      for (let i=0; i < arr.length; i += 2) {
+        parser.pushKey(arr[i]);
+        parser.push(arr[i+1]);
+      }
+    }
   } else {
     for (const tuple of Object.entries(toSet)) {
-      args.push(...tuple);
+      parser.pushKey(tuple[0]);
+      parser.push(tuple[1]);
     }
   }
-
-  return args;
 }
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand: parseMSetArguments.bind(undefined, 'MSET'),
   transformArguments: mSetArguments.bind(undefined, 'MSET'),
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/MSETNX.spec.ts b/packages/client/lib/commands/MSETNX.spec.ts
index 1583d04a94e..0a9f636abc7 100644
--- a/packages/client/lib/commands/MSETNX.spec.ts
+++ b/packages/client/lib/commands/MSETNX.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MSETNX from './MSETNX';
+import { parseArgs } from './generic-transformers';
 
 describe('MSETNX', () => {
   describe('transformArguments', () => {
     it("['key1', 'value1', 'key2', 'value2']", () => {
       assert.deepEqual(
-        MSETNX.transformArguments(['key1', 'value1', 'key2', 'value2']),
+        parseArgs(MSETNX, ['key1', 'value1', 'key2', 'value2']),
         ['MSETNX', 'key1', 'value1', 'key2', 'value2']
       );
     });
 
     it("[['key1', 'value1'], ['key2', 'value2']]", () => {
       assert.deepEqual(
-        MSETNX.transformArguments([['key1', 'value1'], ['key2', 'value2']]),
+        parseArgs(MSETNX, [['key1', 'value1'], ['key2', 'value2']]),
         ['MSETNX', 'key1', 'value1', 'key2', 'value2']
       );
     });
 
     it("{key1: 'value1'. key2: 'value2'}", () => {
       assert.deepEqual(
-        MSETNX.transformArguments({ key1: 'value1', key2: 'value2' }),
+        parseArgs(MSETNX, { key1: 'value1', key2: 'value2' }),
         ['MSETNX', 'key1', 'value1', 'key2', 'value2']
       );
     });
diff --git a/packages/client/lib/commands/MSETNX.ts b/packages/client/lib/commands/MSETNX.ts
index 4867b3ea092..5efad79c349 100644
--- a/packages/client/lib/commands/MSETNX.ts
+++ b/packages/client/lib/commands/MSETNX.ts
@@ -1,9 +1,10 @@
 import { SimpleStringReply, Command } from '../RESP/types';
-import { mSetArguments } from './MSET';
+import { mSetArguments, parseMSetArguments } from './MSET';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand: parseMSetArguments.bind(undefined, 'MSETNX'),
   transformArguments: mSetArguments.bind(undefined, 'MSETNX'),
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/OBJECT_ENCODING.spec.ts b/packages/client/lib/commands/OBJECT_ENCODING.spec.ts
index 48146f12924..34f82be9b8d 100644
--- a/packages/client/lib/commands/OBJECT_ENCODING.spec.ts
+++ b/packages/client/lib/commands/OBJECT_ENCODING.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJECT_ENCODING from './OBJECT_ENCODING';
+import { parseArgs } from './generic-transformers';
 
 describe('OBJECT ENCODING', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      OBJECT_ENCODING.transformArguments('key'),
+      parseArgs(OBJECT_ENCODING, 'key'),
       ['OBJECT', 'ENCODING', 'key']
     );
   });
diff --git a/packages/client/lib/commands/OBJECT_ENCODING.ts b/packages/client/lib/commands/OBJECT_ENCODING.ts
index e74c3f99ebd..9cd5dbf4c78 100644
--- a/packages/client/lib/commands/OBJECT_ENCODING.ts
+++ b/packages/client/lib/commands/OBJECT_ENCODING.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['OBJECT', 'ENCODING', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['OBJECT', 'ENCODING']);
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/OBJECT_FREQ.spec.ts b/packages/client/lib/commands/OBJECT_FREQ.spec.ts
index cbad72c308d..081501b12e6 100644
--- a/packages/client/lib/commands/OBJECT_FREQ.spec.ts
+++ b/packages/client/lib/commands/OBJECT_FREQ.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJECT_FREQ from './OBJECT_FREQ';
+import { parseArgs } from './generic-transformers';
 
 describe('OBJECT FREQ', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      OBJECT_FREQ.transformArguments('key'),
+      parseArgs(OBJECT_FREQ, 'key'),
       ['OBJECT', 'FREQ', 'key']
     );
   });
diff --git a/packages/client/lib/commands/OBJECT_FREQ.ts b/packages/client/lib/commands/OBJECT_FREQ.ts
index b6757c6c57b..910951257eb 100644
--- a/packages/client/lib/commands/OBJECT_FREQ.ts
+++ b/packages/client/lib/commands/OBJECT_FREQ.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['OBJECT', 'FREQ', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['OBJECT', 'FREQ']);
+    parser.push(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/OBJECT_IDLETIME.spec.ts b/packages/client/lib/commands/OBJECT_IDLETIME.spec.ts
index 51866427c81..30d47b8133f 100644
--- a/packages/client/lib/commands/OBJECT_IDLETIME.spec.ts
+++ b/packages/client/lib/commands/OBJECT_IDLETIME.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJECT_IDLETIME from './OBJECT_IDLETIME';
+import { parseArgs } from './generic-transformers';
 
 describe('OBJECT IDLETIME', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      OBJECT_IDLETIME.transformArguments('key'),
+      parseArgs(OBJECT_IDLETIME, 'key'),
       ['OBJECT', 'IDLETIME', 'key']
     );
   });
diff --git a/packages/client/lib/commands/OBJECT_IDLETIME.ts b/packages/client/lib/commands/OBJECT_IDLETIME.ts
index f0fef24e2d8..7471aa35a31 100644
--- a/packages/client/lib/commands/OBJECT_IDLETIME.ts
+++ b/packages/client/lib/commands/OBJECT_IDLETIME.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['OBJECT', 'IDLETIME', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['OBJECT', 'IDLETIME']);
+    parser.push(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/OBJECT_REFCOUNT.spec.ts b/packages/client/lib/commands/OBJECT_REFCOUNT.spec.ts
index f4309786eb1..8bac08a2e5b 100644
--- a/packages/client/lib/commands/OBJECT_REFCOUNT.spec.ts
+++ b/packages/client/lib/commands/OBJECT_REFCOUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJECT_REFCOUNT from './OBJECT_REFCOUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('OBJECT REFCOUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      OBJECT_REFCOUNT.transformArguments('key'),
+      parseArgs(OBJECT_REFCOUNT, 'key'),
       ['OBJECT', 'REFCOUNT', 'key']
     );
   });
diff --git a/packages/client/lib/commands/OBJECT_REFCOUNT.ts b/packages/client/lib/commands/OBJECT_REFCOUNT.ts
index c8381a76bf7..68c7de23bda 100644
--- a/packages/client/lib/commands/OBJECT_REFCOUNT.ts
+++ b/packages/client/lib/commands/OBJECT_REFCOUNT.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['OBJECT', 'REFCOUNT', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['OBJECT', 'REFCOUNT']);
+    parser.push(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PERSIST.spec.ts b/packages/client/lib/commands/PERSIST.spec.ts
index d778a1c0a5f..fff6d7b3a76 100644
--- a/packages/client/lib/commands/PERSIST.spec.ts
+++ b/packages/client/lib/commands/PERSIST.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PERSIST from './PERSIST';
+import { parseArgs } from './generic-transformers';
 
 describe('PERSIST', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PERSIST.transformArguments('key'),
+      parseArgs(PERSIST, 'key'),
       ['PERSIST', 'key']
     );
   });
diff --git a/packages/client/lib/commands/PERSIST.ts b/packages/client/lib/commands/PERSIST.ts
index 64637fabc14..49cbb59430b 100644
--- a/packages/client/lib/commands/PERSIST.ts
+++ b/packages/client/lib/commands/PERSIST.ts
@@ -1,9 +1,12 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument) {
-    return ['PERSIST', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('PERSIST');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PEXPIRE.spec.ts b/packages/client/lib/commands/PEXPIRE.spec.ts
index 61bfe69e9a1..368bc9b4907 100644
--- a/packages/client/lib/commands/PEXPIRE.spec.ts
+++ b/packages/client/lib/commands/PEXPIRE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PEXPIRE from './PEXPIRE';
+import { parseArgs } from './generic-transformers';
 
 describe('PEXPIRE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        PEXPIRE.transformArguments('key', 1),
+        parseArgs(PEXPIRE, 'key', 1),
         ['PEXPIRE', 'key', '1']
       );
     });
 
     it('with set option', () => {
       assert.deepEqual(
-        PEXPIRE.transformArguments('key', 1, 'GT'),
+        parseArgs(PEXPIRE, 'key', 1, 'GT'),
         ['PEXPIRE', 'key', '1', 'GT']
       );
     });
diff --git a/packages/client/lib/commands/PEXPIRE.ts b/packages/client/lib/commands/PEXPIRE.ts
index 4d64281e922..88484794f2e 100644
--- a/packages/client/lib/commands/PEXPIRE.ts
+++ b/packages/client/lib/commands/PEXPIRE.ts
@@ -1,20 +1,27 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     ms: number,
     mode?: 'NX' | 'XX' | 'GT' | 'LT'
   ) {
-    const args = ['PEXPIRE', key, ms.toString()];
+    parser.push('PEXPIRE');
+    parser.pushKey(key);
+    parser.push(ms.toString());
 
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    ms: number,
+    mode?: 'NX' | 'XX' | 'GT' | 'LT'
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PEXPIREAT.spec.ts b/packages/client/lib/commands/PEXPIREAT.spec.ts
index 117c5b512e7..f1053920403 100644
--- a/packages/client/lib/commands/PEXPIREAT.spec.ts
+++ b/packages/client/lib/commands/PEXPIREAT.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PEXPIREAT from './PEXPIREAT';
+import { parseArgs } from './generic-transformers';
 
 describe('PEXPIREAT', () => {
   describe('transformArguments', () => {
     it('number', () => {
       assert.deepEqual(
-        PEXPIREAT.transformArguments('key', 1),
+        parseArgs(PEXPIREAT, 'key', 1),
         ['PEXPIREAT', 'key', '1']
       );
     });
@@ -14,14 +15,14 @@ describe('PEXPIREAT', () => {
     it('date', () => {
       const d = new Date();
       assert.deepEqual(
-        PEXPIREAT.transformArguments('key', d),
+        parseArgs(PEXPIREAT, 'key', d),
         ['PEXPIREAT', 'key', d.getTime().toString()]
       );
     });
 
     it('with set option', () => {
       assert.deepEqual(
-        PEXPIREAT.transformArguments('key', 1, 'XX'),
+        parseArgs(PEXPIREAT, 'key', 1, 'XX'),
         ['PEXPIREAT', 'key', '1', 'XX']
       );
     });
diff --git a/packages/client/lib/commands/PEXPIREAT.ts b/packages/client/lib/commands/PEXPIREAT.ts
index cbae589fba6..8c2060d46b3 100644
--- a/packages/client/lib/commands/PEXPIREAT.ts
+++ b/packages/client/lib/commands/PEXPIREAT.ts
@@ -1,21 +1,28 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformPXAT } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     msTimestamp: number | Date,
     mode?: 'NX' | 'XX' | 'GT' | 'LT'
   ) {
-    const args = ['PEXPIREAT', key, transformPXAT(msTimestamp)];
+    parser.push('PEXPIREAT');
+    parser.pushKey(key);
+    parser.push(transformPXAT(msTimestamp));
 
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    msTimestamp: number | Date,
+    mode?: 'NX' | 'XX' | 'GT' | 'LT'
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PEXPIRETIME.spec.ts b/packages/client/lib/commands/PEXPIRETIME.spec.ts
index 25a8293ec59..dbfc69e80dc 100644
--- a/packages/client/lib/commands/PEXPIRETIME.spec.ts
+++ b/packages/client/lib/commands/PEXPIRETIME.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PEXPIRETIME from './PEXPIRETIME';
+import { parseArgs } from './generic-transformers';
 
 describe('PEXPIRETIME', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      PEXPIRETIME.transformArguments('key'),
+      parseArgs(PEXPIRETIME, 'key'),
       ['PEXPIRETIME', 'key']
     );
   });
diff --git a/packages/client/lib/commands/PEXPIRETIME.ts b/packages/client/lib/commands/PEXPIRETIME.ts
index e228351fa0e..2aba75a2da8 100644
--- a/packages/client/lib/commands/PEXPIRETIME.ts
+++ b/packages/client/lib/commands/PEXPIRETIME.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['PEXPIRETIME', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('PEXPIRETIME');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PFADD.spec.ts b/packages/client/lib/commands/PFADD.spec.ts
index 04ba44164df..55c4311e638 100644
--- a/packages/client/lib/commands/PFADD.spec.ts
+++ b/packages/client/lib/commands/PFADD.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PFADD from './PFADD';
+import { parseArgs } from './generic-transformers';
 
 describe('PFADD', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        PFADD.transformArguments('key', 'element'),
+        parseArgs(PFADD, 'key', 'element'),
         ['PFADD', 'key', 'element']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        PFADD.transformArguments('key', ['1', '2']),
+        parseArgs(PFADD, 'key', ['1', '2']),
         ['PFADD', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/PFADD.ts b/packages/client/lib/commands/PFADD.ts
index d7f198fbe55..ffbba926e42 100644
--- a/packages/client/lib/commands/PFADD.ts
+++ b/packages/client/lib/commands/PFADD.ts
@@ -1,14 +1,17 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, element?: RedisVariadicArgument) {
-    const args = ['PFADD', key];
-    if (!element) return args;
-
-    return pushVariadicArguments(args, element);
+  parseCommand(parser: CommandParser, key: RedisArgument, element?: RedisVariadicArgument) {
+    parser.push('PFADD')
+    parser.pushKey(key);
+    if (element) {
+      parser.pushVariadic(element);
+    }
   },
+  transformArguments(key: RedisArgument, element?: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PFCOUNT.spec.ts b/packages/client/lib/commands/PFCOUNT.spec.ts
index ebb54ea1d72..aec2ebecf0b 100644
--- a/packages/client/lib/commands/PFCOUNT.spec.ts
+++ b/packages/client/lib/commands/PFCOUNT.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PFCOUNT from './PFCOUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('PFCOUNT', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        PFCOUNT.transformArguments('key'),
+        parseArgs(PFCOUNT, 'key'),
         ['PFCOUNT', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        PFCOUNT.transformArguments(['1', '2']),
+        parseArgs(PFCOUNT, ['1', '2']),
         ['PFCOUNT', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/PFCOUNT.ts b/packages/client/lib/commands/PFCOUNT.ts
index 5b46eb00d92..95d0a14223d 100644
--- a/packages/client/lib/commands/PFCOUNT.ts
+++ b/packages/client/lib/commands/PFCOUNT.ts
@@ -1,11 +1,14 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisVariadicArgument) {
-    return pushVariadicArguments(['PFCOUNT'], key);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.push('PFCOUNT');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PFMERGE.spec.ts b/packages/client/lib/commands/PFMERGE.spec.ts
index bb2444b3ef1..a286e932913 100644
--- a/packages/client/lib/commands/PFMERGE.spec.ts
+++ b/packages/client/lib/commands/PFMERGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PFMERGE from './PFMERGE';
+import { parseArgs } from './generic-transformers';
 
 describe('PFMERGE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        PFMERGE.transformArguments('destination', 'source'),
+        parseArgs(PFMERGE, 'destination', 'source'),
         ['PFMERGE', 'destination', 'source']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        PFMERGE.transformArguments('destination', ['1', '2']),
+        parseArgs(PFMERGE, 'destination', ['1', '2']),
         ['PFMERGE', 'destination', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/PFMERGE.ts b/packages/client/lib/commands/PFMERGE.ts
index eeeeb5173db..01301476b79 100644
--- a/packages/client/lib/commands/PFMERGE.ts
+++ b/packages/client/lib/commands/PFMERGE.ts
@@ -1,16 +1,23 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     destination: RedisArgument,
-    source?: RedisVariadicArgument
+    sources?: RedisVariadicArgument
   ) {
-    const args = ['PFMERGE', destination];
-    if (!source) return args;
-
-    return pushVariadicArguments(args, source);
+    parser.push('PFMERGE');
+    parser.pushKey(destination);
+    if (sources) {
+      parser.pushKeys(sources);
+    }
   },
+  transformArguments(
+    destination: RedisArgument,
+    sources?: RedisVariadicArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PING.spec.ts b/packages/client/lib/commands/PING.spec.ts
index 0cd75a6a8de..56f513685f4 100644
--- a/packages/client/lib/commands/PING.spec.ts
+++ b/packages/client/lib/commands/PING.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PING from './PING';
+import { parseArgs } from './generic-transformers';
 
 describe('PING', () => {
   describe('transformArguments', () => {
     it('default', () => {
       assert.deepEqual(
-        PING.transformArguments(),
+        parseArgs(PING),
         ['PING']
       );
     });
 
     it('with message', () => {
       assert.deepEqual(
-        PING.transformArguments('message'),
+        parseArgs(PING, 'message'),
         ['PING', 'message']
       );
     });
diff --git a/packages/client/lib/commands/PING.ts b/packages/client/lib/commands/PING.ts
index 7f6fd31047e..6dcd2aa8e9f 100644
--- a/packages/client/lib/commands/PING.ts
+++ b/packages/client/lib/commands/PING.ts
@@ -1,15 +1,15 @@
 import { RedisArgument, SimpleStringReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(message?: RedisArgument) {
-    const args: Array<RedisArgument> = ['PING'];
+  parseCommand(parser: CommandParser, message?: RedisArgument) {
+    parser.push('PING');
     if (message) {
-      args.push(message);
+      parser.push(message);
     }
-
-    return args;
   },
+  transformArguments(message?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply | BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PSETEX.spec.ts b/packages/client/lib/commands/PSETEX.spec.ts
index fd7bcd2dff2..8580e2f8e9d 100644
--- a/packages/client/lib/commands/PSETEX.spec.ts
+++ b/packages/client/lib/commands/PSETEX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PSETEX from './PSETEX';
+import { parseArgs } from './generic-transformers';
 
 describe('PSETEX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PSETEX.transformArguments('key', 1, 'value'),
+      parseArgs(PSETEX, 'key', 1, 'value'),
       ['PSETEX', 'key', '1', 'value']
     );
   });
diff --git a/packages/client/lib/commands/PSETEX.ts b/packages/client/lib/commands/PSETEX.ts
index 4e345a1a1c9..5855f97788d 100644
--- a/packages/client/lib/commands/PSETEX.ts
+++ b/packages/client/lib/commands/PSETEX.ts
@@ -1,18 +1,13 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    ms: number,
-    value: RedisArgument
-  ) {
-    return [
-      'PSETEX',
-      key,
-      ms.toString(),
-      value
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, ms: number, value: RedisArgument) {
+    parser.push('PSETEX');
+    parser.pushKey(key);
+    parser.pushVariadic([ms.toString(), value]);
   },
+  transformArguments(key: RedisArgument, ms: number, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PTTL.spec.ts b/packages/client/lib/commands/PTTL.spec.ts
index 65a9f5dd0ff..deb04bad97e 100644
--- a/packages/client/lib/commands/PTTL.spec.ts
+++ b/packages/client/lib/commands/PTTL.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PTTL from './PTTL';
+import { parseArgs } from './generic-transformers';
 
 describe('PTTL', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PTTL.transformArguments('key'),
+      parseArgs(PTTL, 'key'),
       ['PTTL', 'key']
     );
   });
diff --git a/packages/client/lib/commands/PTTL.ts b/packages/client/lib/commands/PTTL.ts
index 35854337877..226b1183cf9 100644
--- a/packages/client/lib/commands/PTTL.ts
+++ b/packages/client/lib/commands/PTTL.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['PTTL', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('PTTL');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PUBLISH.spec.ts b/packages/client/lib/commands/PUBLISH.spec.ts
index ec1f108e5ee..930adc8c4d7 100644
--- a/packages/client/lib/commands/PUBLISH.spec.ts
+++ b/packages/client/lib/commands/PUBLISH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBLISH from './PUBLISH';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBLISH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PUBLISH.transformArguments('channel', 'message'),
+      parseArgs(PUBLISH, 'channel', 'message'),
       ['PUBLISH', 'channel', 'message']
     );
   });
diff --git a/packages/client/lib/commands/PUBLISH.ts b/packages/client/lib/commands/PUBLISH.ts
index e790ff16c4d..38c09337981 100644
--- a/packages/client/lib/commands/PUBLISH.ts
+++ b/packages/client/lib/commands/PUBLISH.ts
@@ -1,11 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
   IS_FORWARD_COMMAND: true,
-  transformArguments(channel: RedisArgument, message: RedisArgument) {
-    return ['PUBLISH', channel, message];
+  parseCommand(parser: CommandParser, channel: RedisArgument, message: RedisArgument) {
+    parser.pushVariadic(['PUBLISH', channel, message]);
   },
+  transformArguments(channel: RedisArgument, message: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PUBSUB_CHANNELS.spec.ts b/packages/client/lib/commands/PUBSUB_CHANNELS.spec.ts
index 2fe02523ed1..369e339a497 100644
--- a/packages/client/lib/commands/PUBSUB_CHANNELS.spec.ts
+++ b/packages/client/lib/commands/PUBSUB_CHANNELS.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBSUB_CHANNELS from './PUBSUB_CHANNELS';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBSUB CHANNELS', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        PUBSUB_CHANNELS.transformArguments(),
+        parseArgs(PUBSUB_CHANNELS),
         ['PUBSUB', 'CHANNELS']
       );
     });
 
     it('with pattern', () => {
       assert.deepEqual(
-        PUBSUB_CHANNELS.transformArguments('patter*'),
+        parseArgs(PUBSUB_CHANNELS, 'patter*'),
         ['PUBSUB', 'CHANNELS', 'patter*']
       );
     });
diff --git a/packages/client/lib/commands/PUBSUB_CHANNELS.ts b/packages/client/lib/commands/PUBSUB_CHANNELS.ts
index 4bf7abd75dc..beba2286a12 100644
--- a/packages/client/lib/commands/PUBSUB_CHANNELS.ts
+++ b/packages/client/lib/commands/PUBSUB_CHANNELS.ts
@@ -1,17 +1,17 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(pattern?: RedisArgument) {
-    const args: Array<RedisArgument> = ['PUBSUB', 'CHANNELS'];
+  parseCommand(parser: CommandParser, pattern?: RedisArgument) {
+    parser.pushVariadic(['PUBSUB', 'CHANNELS']);
 
     if (pattern) {
-      args.push(pattern);
+      parser.push(pattern);
     }
-
-    return args;
   },
+  transformArguments(pattern?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/PUBSUB_NUMPAT.spec.ts b/packages/client/lib/commands/PUBSUB_NUMPAT.spec.ts
index 43a2b4b5c0e..d75256bb43c 100644
--- a/packages/client/lib/commands/PUBSUB_NUMPAT.spec.ts
+++ b/packages/client/lib/commands/PUBSUB_NUMPAT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBSUB_NUMPAT from './PUBSUB_NUMPAT';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBSUB NUMPAT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PUBSUB_NUMPAT.transformArguments(),
+      parseArgs(PUBSUB_NUMPAT),
       ['PUBSUB', 'NUMPAT']
     );
   });
diff --git a/packages/client/lib/commands/PUBSUB_NUMPAT.ts b/packages/client/lib/commands/PUBSUB_NUMPAT.ts
index e8a0738dc72..11519795aba 100644
--- a/packages/client/lib/commands/PUBSUB_NUMPAT.ts
+++ b/packages/client/lib/commands/PUBSUB_NUMPAT.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['PUBSUB', 'NUMPAT'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['PUBSUB', 'NUMPAT']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PUBSUB_NUMSUB.spec.ts b/packages/client/lib/commands/PUBSUB_NUMSUB.spec.ts
index 151dc219288..11339ae2bb5 100644
--- a/packages/client/lib/commands/PUBSUB_NUMSUB.spec.ts
+++ b/packages/client/lib/commands/PUBSUB_NUMSUB.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBSUB_NUMSUB from './PUBSUB_NUMSUB';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBSUB NUMSUB', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        PUBSUB_NUMSUB.transformArguments(),
+        parseArgs(PUBSUB_NUMSUB),
         ['PUBSUB', 'NUMSUB']
       );
     });
 
     it('string', () => {
       assert.deepEqual(
-        PUBSUB_NUMSUB.transformArguments('channel'),
+        parseArgs(PUBSUB_NUMSUB, 'channel'),
         ['PUBSUB', 'NUMSUB', 'channel']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        PUBSUB_NUMSUB.transformArguments(['1', '2']),
+        parseArgs(PUBSUB_NUMSUB, ['1', '2']),
         ['PUBSUB', 'NUMSUB', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/PUBSUB_NUMSUB.ts b/packages/client/lib/commands/PUBSUB_NUMSUB.ts
index 1f7c41f5bdd..8289040ab50 100644
--- a/packages/client/lib/commands/PUBSUB_NUMSUB.ts
+++ b/packages/client/lib/commands/PUBSUB_NUMSUB.ts
@@ -1,16 +1,18 @@
 import { ArrayReply, BlobStringReply, NumberReply, UnwrapReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(channels?: RedisVariadicArgument) {
-    const args = ['PUBSUB', 'NUMSUB'];
+  parseCommand(parser: CommandParser, channels?: RedisVariadicArgument) {
+    parser.pushVariadic(['PUBSUB', 'NUMSUB']);
 
-    if (channels) return pushVariadicArguments(args, channels);
-
-    return args;
+    if (channels) {
+      parser.pushVariadic(channels);
+    }
   },
+  transformArguments(channels?: RedisVariadicArgument) { return [] },
   transformReply(rawReply: UnwrapReply<ArrayReply<BlobStringReply | NumberReply>>) {
     const reply = Object.create(null);
     let i = 0;
diff --git a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
index 77982b34670..36597a9cfd8 100644
--- a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
+++ b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBSUB_SHARDCHANNELS from './PUBSUB_SHARDCHANNELS';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBSUB SHARDCHANNELS', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('PUBSUB SHARDCHANNELS', () => {
   describe('transformArguments', () => {
     it('without pattern', () => {
       assert.deepEqual(
-        PUBSUB_SHARDCHANNELS.transformArguments(),
+        parseArgs(PUBSUB_SHARDCHANNELS),
         ['PUBSUB', 'SHARDCHANNELS']
       );
     });
 
     it('with pattern', () => {
       assert.deepEqual(
-        PUBSUB_SHARDCHANNELS.transformArguments('patter*'),
+        parseArgs(PUBSUB_SHARDCHANNELS, 'patter*'),
         ['PUBSUB', 'SHARDCHANNELS', 'patter*']
       );
     });
diff --git a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
index 74d78c02614..2c9994676ad 100644
--- a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
+++ b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
@@ -1,16 +1,16 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(pattern?: RedisArgument) {
-    const args: Array<RedisArgument> = ['PUBSUB', 'SHARDCHANNELS'];
+  parseCommand(parser: CommandParser, pattern?: RedisArgument) {
+    parser.pushVariadic(['PUBSUB', 'SHARDCHANNELS']);
 
     if (pattern) {
-      args.push(pattern);
+      parser.push(pattern);
     }
-
-    return args;
   },
+  transformArguments(pattern?: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
index e036a6eae5b..e335941897d 100644
--- a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
+++ b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PUBSUB_SHARDNUMSUB from './PUBSUB_SHARDNUMSUB';
+import { parseArgs } from './generic-transformers';
 
 describe('PUBSUB SHARDNUMSUB', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,21 +9,21 @@ describe('PUBSUB SHARDNUMSUB', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        PUBSUB_SHARDNUMSUB.transformArguments(),
+        parseArgs(PUBSUB_SHARDNUMSUB),
         ['PUBSUB', 'SHARDNUMSUB']
       );
     });
 
     it('string', () => {
       assert.deepEqual(
-        PUBSUB_SHARDNUMSUB.transformArguments('channel'),
+        parseArgs(PUBSUB_SHARDNUMSUB, 'channel'),
         ['PUBSUB', 'SHARDNUMSUB', 'channel']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        PUBSUB_SHARDNUMSUB.transformArguments(['1', '2']),
+        parseArgs(PUBSUB_SHARDNUMSUB, ['1', '2']),
         ['PUBSUB', 'SHARDNUMSUB', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
index 0ef82477006..4ecdbc6ef1f 100644
--- a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
+++ b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
@@ -1,16 +1,18 @@
 import { ArrayReply, BlobStringReply, NumberReply, UnwrapReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(channels?: RedisVariadicArgument) {
-    const args = ['PUBSUB', 'SHARDNUMSUB'];
+  parseCommand(parser: CommandParser, channels?: RedisVariadicArgument) {
+    parser.pushVariadic(['PUBSUB', 'SHARDNUMSUB']);
 
-    if (channels) return pushVariadicArguments(args, channels);
-
-    return args;
+    if (channels) {
+      parser.pushVariadic(channels);
+    }
   },
+  transformArguments(channels?: RedisVariadicArgument) { return [] },
   transformReply(reply: UnwrapReply<ArrayReply<BlobStringReply | NumberReply>>) {
     const transformedReply: Record<string, NumberReply> = Object.create(null);
 
diff --git a/packages/client/lib/commands/RANDOMKEY.spec.ts b/packages/client/lib/commands/RANDOMKEY.spec.ts
index 31de60d7a99..f86617a3b75 100644
--- a/packages/client/lib/commands/RANDOMKEY.spec.ts
+++ b/packages/client/lib/commands/RANDOMKEY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RANDOMKEY from './RANDOMKEY';
+import { parseArgs } from './generic-transformers';
 
 describe('RANDOMKEY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RANDOMKEY.transformArguments(),
+      parseArgs(RANDOMKEY),
       ['RANDOMKEY']
     );
   });
diff --git a/packages/client/lib/commands/RANDOMKEY.ts b/packages/client/lib/commands/RANDOMKEY.ts
index 42028ebbe38..c95c3ab5b5d 100644
--- a/packages/client/lib/commands/RANDOMKEY.ts
+++ b/packages/client/lib/commands/RANDOMKEY.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['RANDOMKEY'];
+  parseCommand(parser: CommandParser) {
+    parser.push('RANDOMKEY');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/READONLY.spec.ts b/packages/client/lib/commands/READONLY.spec.ts
index 14bb047349a..ac303322330 100644
--- a/packages/client/lib/commands/READONLY.spec.ts
+++ b/packages/client/lib/commands/READONLY.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import READONLY from './READONLY';
+import { parseArgs } from './generic-transformers';
 
 describe('READONLY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      READONLY.transformArguments(),
+      parseArgs(READONLY),
       ['READONLY']
     );
   });
diff --git a/packages/client/lib/commands/READONLY.ts b/packages/client/lib/commands/READONLY.ts
index bb15834550e..cbb001c3279 100644
--- a/packages/client/lib/commands/READONLY.ts
+++ b/packages/client/lib/commands/READONLY.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['READONLY'];
+  parseCommand(parser: CommandParser) {
+    parser.push('READONLY');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/READWRITE.spec.ts b/packages/client/lib/commands/READWRITE.spec.ts
index 94a88a0dcc7..cc3f99a5d16 100644
--- a/packages/client/lib/commands/READWRITE.spec.ts
+++ b/packages/client/lib/commands/READWRITE.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import READWRITE from './READWRITE';
+import { parseArgs } from './generic-transformers';
 
 describe('READWRITE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      READWRITE.transformArguments(),
+      parseArgs(READWRITE),
       ['READWRITE']
     );
   });
diff --git a/packages/client/lib/commands/READWRITE.ts b/packages/client/lib/commands/READWRITE.ts
index fe70e15d4c8..996b0c78bde 100644
--- a/packages/client/lib/commands/READWRITE.ts
+++ b/packages/client/lib/commands/READWRITE.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['READWRITE'];
+  parseCommand(parser: CommandParser) {
+    parser.push('READWRITE');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RENAME.spec.ts b/packages/client/lib/commands/RENAME.spec.ts
index cf3dccbf3e7..05dd9417b96 100644
--- a/packages/client/lib/commands/RENAME.spec.ts
+++ b/packages/client/lib/commands/RENAME.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RENAME from './RENAME';
+import { parseArgs } from './generic-transformers';
 
 describe('RENAME', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RENAME.transformArguments('source', 'destination'),
+      parseArgs(RENAME, 'source', 'destination'),
       ['RENAME', 'source', 'destination']
     );
   });
diff --git a/packages/client/lib/commands/RENAME.ts b/packages/client/lib/commands/RENAME.ts
index 16e883d0532..95c7ae4fdb5 100644
--- a/packages/client/lib/commands/RENAME.ts
+++ b/packages/client/lib/commands/RENAME.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, newKey: RedisArgument) {
-    return ['RENAME', key, newKey];
+  parseCommand(parser: CommandParser, key: RedisArgument, newKey: RedisArgument) {
+    parser.push('RENAME');
+    parser.pushKeys([key, newKey]);
   },
+  transformArguments(key: RedisArgument, newKey: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RENAMENX.spec.ts b/packages/client/lib/commands/RENAMENX.spec.ts
index 5f83933e957..2367b453322 100644
--- a/packages/client/lib/commands/RENAMENX.spec.ts
+++ b/packages/client/lib/commands/RENAMENX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RENAMENX from './RENAMENX';
+import { parseArgs } from './generic-transformers';
 
 describe('RENAMENX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RENAMENX.transformArguments('source', 'destination'),
+      parseArgs(RENAMENX, 'source', 'destination'),
       ['RENAMENX', 'source', 'destination']
     );
   });
diff --git a/packages/client/lib/commands/RENAMENX.ts b/packages/client/lib/commands/RENAMENX.ts
index 3a4f155d5a7..626ed8edb76 100644
--- a/packages/client/lib/commands/RENAMENX.ts
+++ b/packages/client/lib/commands/RENAMENX.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, newKey: RedisArgument) {
-    return ['RENAMENX', key, newKey];
+  parseCommand(parser: CommandParser, key: RedisArgument, newKey: RedisArgument) {
+    parser.push('RENAMENX');
+    parser.pushKeys([key, newKey]);
   },
+  transformArguments(key: RedisArgument, newKey: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/REPLICAOF.spec.ts b/packages/client/lib/commands/REPLICAOF.spec.ts
index 77dbe060450..13668639494 100644
--- a/packages/client/lib/commands/REPLICAOF.spec.ts
+++ b/packages/client/lib/commands/REPLICAOF.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import REPLICAOF from './REPLICAOF';
+import { parseArgs } from './generic-transformers';
 
 describe('REPLICAOF', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      REPLICAOF.transformArguments('host', 1),
+      parseArgs(REPLICAOF, 'host', 1),
       ['REPLICAOF', 'host', '1']
     );
   });
diff --git a/packages/client/lib/commands/REPLICAOF.ts b/packages/client/lib/commands/REPLICAOF.ts
index 4e2f69f7265..d1a2d9d64cf 100644
--- a/packages/client/lib/commands/REPLICAOF.ts
+++ b/packages/client/lib/commands/REPLICAOF.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(host: string, port: number) {
-    return ['REPLICAOF', host, port.toString()];
+  parseCommand(parser: CommandParser, host: string, port: number) {
+    parser.pushVariadic(['REPLICAOF', host, port.toString()]);
   },
+  transformArguments(host: string, port: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RESTORE-ASKING.spec.ts b/packages/client/lib/commands/RESTORE-ASKING.spec.ts
index 855196b9776..1258cf68e2d 100644
--- a/packages/client/lib/commands/RESTORE-ASKING.spec.ts
+++ b/packages/client/lib/commands/RESTORE-ASKING.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import RESTORE_ASKING from './RESTORE-ASKING';
+import { parseArgs } from './generic-transformers';
 
 describe('RESTORE-ASKING', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RESTORE_ASKING.transformArguments(),
+      parseArgs(RESTORE_ASKING),
       ['RESTORE-ASKING']
     );
   });
diff --git a/packages/client/lib/commands/RESTORE-ASKING.ts b/packages/client/lib/commands/RESTORE-ASKING.ts
index 14f6dcbeab3..08452432631 100644
--- a/packages/client/lib/commands/RESTORE-ASKING.ts
+++ b/packages/client/lib/commands/RESTORE-ASKING.ts
@@ -1,10 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['RESTORE-ASKING'];
+  parseCommand(parser: CommandParser) {
+    parser.push('RESTORE-ASKING');
   },
+
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RESTORE.spec.ts b/packages/client/lib/commands/RESTORE.spec.ts
index 6b814e7325a..6083b2eb1a5 100644
--- a/packages/client/lib/commands/RESTORE.spec.ts
+++ b/packages/client/lib/commands/RESTORE.spec.ts
@@ -2,19 +2,20 @@ import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RESTORE from './RESTORE';
 import { RESP_TYPES } from '../RESP/decoder';
+import { parseArgs } from './generic-transformers';
 
 describe('RESTORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value'),
+        parseArgs(RESTORE, 'key', 0, 'value'),
         ['RESTORE', 'key', '0', 'value']
       );
     });
 
     it('with REPLACE', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value', {
+        parseArgs(RESTORE, 'key', 0, 'value', {
           REPLACE: true
         }),
         ['RESTORE', 'key', '0', 'value', 'REPLACE']
@@ -23,7 +24,7 @@ describe('RESTORE', () => {
 
     it('with ABSTTL', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value', {
+        parseArgs(RESTORE, 'key', 0, 'value', {
           ABSTTL: true
         }),
         ['RESTORE', 'key', '0', 'value', 'ABSTTL']
@@ -32,7 +33,7 @@ describe('RESTORE', () => {
 
     it('with IDLETIME', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value', {
+        parseArgs(RESTORE, 'key', 0, 'value', {
           IDLETIME: 1
         }),
         ['RESTORE', 'key', '0', 'value', 'IDLETIME', '1']
@@ -41,7 +42,7 @@ describe('RESTORE', () => {
 
     it('with FREQ', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value', {
+        parseArgs(RESTORE, 'key', 0, 'value', {
           FREQ: 1
         }),
         ['RESTORE', 'key', '0', 'value', 'FREQ', '1']
@@ -50,7 +51,7 @@ describe('RESTORE', () => {
 
     it('with REPLACE, ABSTTL, IDLETIME and FREQ', () => {
       assert.deepEqual(
-        RESTORE.transformArguments('key', 0, 'value', {
+        parseArgs(RESTORE, 'key', 0, 'value', {
           REPLACE: true,
           ABSTTL: true,
           IDLETIME: 1,
diff --git a/packages/client/lib/commands/RESTORE.ts b/packages/client/lib/commands/RESTORE.ts
index b24c5b569f9..b4eb480bf08 100644
--- a/packages/client/lib/commands/RESTORE.ts
+++ b/packages/client/lib/commands/RESTORE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface RestoreOptions {
   REPLACE?: boolean;
@@ -10,31 +11,38 @@ export interface RestoreOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     ttl: number,
     serializedValue: RedisArgument,
     options?: RestoreOptions
   ) {
-    const args =  ['RESTORE', key, ttl.toString(), serializedValue];
+    parser.push('RESTORE');
+    parser.pushKey(key);
+    parser.pushVariadic([ttl.toString(), serializedValue]);
 
     if (options?.REPLACE) {
-      args.push('REPLACE');
+      parser.push('REPLACE');
     }
 
     if (options?.ABSTTL) {
-      args.push('ABSTTL');
+      parser.push('ABSTTL');
     }
 
     if (options?.IDLETIME) {
-      args.push('IDLETIME', options.IDLETIME.toString());
+      parser.pushVariadic(['IDLETIME', options.IDLETIME.toString()]);
     }
 
     if (options?.FREQ) {
-      args.push('FREQ', options.FREQ.toString());
+      parser.pushVariadic(['FREQ', options.FREQ.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    ttl: number,
+    serializedValue: RedisArgument,
+    options?: RestoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ROLE.spec.ts b/packages/client/lib/commands/ROLE.spec.ts
index c57ba5ba1f0..09ce6ed3427 100644
--- a/packages/client/lib/commands/ROLE.spec.ts
+++ b/packages/client/lib/commands/ROLE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ROLE from './ROLE';
+import { parseArgs } from './generic-transformers';
 
 describe('ROLE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ROLE.transformArguments(),
+      parseArgs(ROLE),
       ['ROLE']
     );
   });
diff --git a/packages/client/lib/commands/ROLE.ts b/packages/client/lib/commands/ROLE.ts
index 7828e53fb61..953c3852ae9 100644
--- a/packages/client/lib/commands/ROLE.ts
+++ b/packages/client/lib/commands/ROLE.ts
@@ -1,4 +1,5 @@
 import { BlobStringReply, NumberReply, ArrayReply, TuplesReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type MasterRole = [
   role: BlobStringReply<'master'>,
@@ -24,9 +25,10 @@ type Role = TuplesReply<MasterRole | SlaveRole | SentinelRole>;
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['ROLE'];
+  parseCommand(parser: CommandParser) {
+    parser.push('ROLE');
   },
+  transformArguments() { return [] },
   transformReply(reply: UnwrapReply<Role>) {
     switch (reply[0] as unknown as UnwrapReply<typeof reply[0]>) {
       case 'master': {
diff --git a/packages/client/lib/commands/RPOP.spec.ts b/packages/client/lib/commands/RPOP.spec.ts
index 8ac5cb290f4..844965eae1a 100644
--- a/packages/client/lib/commands/RPOP.spec.ts
+++ b/packages/client/lib/commands/RPOP.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RPOP from './RPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('RPOP', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RPOP.transformArguments('key'),
+      parseArgs(RPOP, 'key'),
       ['RPOP', 'key']
     );
   });
diff --git a/packages/client/lib/commands/RPOP.ts b/packages/client/lib/commands/RPOP.ts
index f7d0b33d3af..913fb93e4de 100644
--- a/packages/client/lib/commands/RPOP.ts
+++ b/packages/client/lib/commands/RPOP.ts
@@ -1,9 +1,12 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument) {
-    return ['RPOP', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('RPOP');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RPOPLPUSH.spec.ts b/packages/client/lib/commands/RPOPLPUSH.spec.ts
index 59458fc0aa8..728d600bc9d 100644
--- a/packages/client/lib/commands/RPOPLPUSH.spec.ts
+++ b/packages/client/lib/commands/RPOPLPUSH.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RPOPLPUSH from './RPOPLPUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('RPOPLPUSH', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RPOPLPUSH.transformArguments('source', 'destination'),
+      parseArgs(RPOPLPUSH, 'source', 'destination'),
       ['RPOPLPUSH', 'source', 'destination']
     );
   });
diff --git a/packages/client/lib/commands/RPOPLPUSH.ts b/packages/client/lib/commands/RPOPLPUSH.ts
index 1a5e1cc59bc..d6c68fc5301 100644
--- a/packages/client/lib/commands/RPOPLPUSH.ts
+++ b/packages/client/lib/commands/RPOPLPUSH.ts
@@ -1,12 +1,12 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    source: RedisArgument,
-    destination: RedisArgument
-  ) {
-    return ['RPOPLPUSH', source, destination];
+  parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument) {
+    parser.push('RPOPLPUSH');
+    parser.pushKeys([source, destination]);
   },
+  transformArguments(source: RedisArgument, destination: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RPOP_COUNT.spec.ts b/packages/client/lib/commands/RPOP_COUNT.spec.ts
index 14f1854b8bc..e055d8655b5 100644
--- a/packages/client/lib/commands/RPOP_COUNT.spec.ts
+++ b/packages/client/lib/commands/RPOP_COUNT.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RPOP_COUNT from './RPOP_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('RPOP COUNT', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      RPOP_COUNT.transformArguments('key', 1),
+      parseArgs(RPOP_COUNT, 'key', 1),
       ['RPOP', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/RPOP_COUNT.ts b/packages/client/lib/commands/RPOP_COUNT.ts
index b60dec6ab9d..35dea8312f8 100644
--- a/packages/client/lib/commands/RPOP_COUNT.ts
+++ b/packages/client/lib/commands/RPOP_COUNT.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, ArrayReply, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['RPOP', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('RPOP');
+    parser.pushKey(key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RPUSH.spec.ts b/packages/client/lib/commands/RPUSH.spec.ts
index 06078d75951..559fb7a2746 100644
--- a/packages/client/lib/commands/RPUSH.spec.ts
+++ b/packages/client/lib/commands/RPUSH.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RPUSH from './RPUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('RPUSH', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        RPUSH.transformArguments('key', 'element'),
+        parseArgs(RPUSH, 'key', 'element'),
         ['RPUSH', 'key', 'element']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        RPUSH.transformArguments('key', ['1', '2']),
+        parseArgs(RPUSH, 'key', ['1', '2']),
         ['RPUSH', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/RPUSH.ts b/packages/client/lib/commands/RPUSH.ts
index 4b048777389..433f6284d61 100644
--- a/packages/client/lib/commands/RPUSH.ts
+++ b/packages/client/lib/commands/RPUSH.ts
@@ -1,13 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    element: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['RPUSH', key], element);
+  parseCommand(parser: CommandParser, key: RedisArgument, element: RedisVariadicArgument) {
+    parser.push('RPUSH');
+    parser.pushKey(key);
+    parser.pushVariadic(element);
   },
+  transformArguments(key: RedisArgument, element: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/RPUSHX.spec.ts b/packages/client/lib/commands/RPUSHX.spec.ts
index 5adaa8b263a..b9fb660c5bc 100644
--- a/packages/client/lib/commands/RPUSHX.spec.ts
+++ b/packages/client/lib/commands/RPUSHX.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RPUSHX from './RPUSHX';
+import { parseArgs } from './generic-transformers';
 
 describe('RPUSHX', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        RPUSHX.transformArguments('key', 'element'),
+        parseArgs(RPUSHX, 'key', 'element'),
         ['RPUSHX', 'key', 'element']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        RPUSHX.transformArguments('key', ['1', '2']),
+        parseArgs(RPUSHX, 'key', ['1', '2']),
         ['RPUSHX', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/RPUSHX.ts b/packages/client/lib/commands/RPUSHX.ts
index 00b29624b0d..b5df2c55eec 100644
--- a/packages/client/lib/commands/RPUSHX.ts
+++ b/packages/client/lib/commands/RPUSHX.ts
@@ -1,13 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    element: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['RPUSHX', key], element);
+  parseCommand(parser: CommandParser, key: RedisArgument, element: RedisVariadicArgument) {
+    parser.push('RPUSHX');
+    parser.pushKey(key);
+    parser.pushVariadic(element);
   },
+  transformArguments(key: RedisArgument, element: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SADD.spec.ts b/packages/client/lib/commands/SADD.spec.ts
index 77adc1c18ce..179e8602efc 100644
--- a/packages/client/lib/commands/SADD.spec.ts
+++ b/packages/client/lib/commands/SADD.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SADD from './SADD';
+import { parseArgs } from './generic-transformers';
 
 describe('SADD', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SADD.transformArguments('key', 'member'),
+        parseArgs(SADD, 'key', 'member'),
         ['SADD', 'key', 'member']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SADD.transformArguments('key', ['1', '2']),
+        parseArgs(SADD, 'key', ['1', '2']),
         ['SADD', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SADD.ts b/packages/client/lib/commands/SADD.ts
index 2ff5e9263c3..da1d154f375 100644
--- a/packages/client/lib/commands/SADD.ts
+++ b/packages/client/lib/commands/SADD.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, members: RedisVariadicArgument) {
-    return pushVariadicArguments(['SADD', key], members);
+  parseCommand(parser: CommandParser, key: RedisArgument, members: RedisVariadicArgument) {
+    parser.push('SADD');
+    parser.pushKey(key);
+    parser.pushVariadic(members);
   },
+  transformArguments(key: RedisArgument, members: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SAVE.spec.ts b/packages/client/lib/commands/SAVE.spec.ts
index 5c014da7edb..5f0074f7492 100644
--- a/packages/client/lib/commands/SAVE.spec.ts
+++ b/packages/client/lib/commands/SAVE.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import SAVE from './SAVE';
+import { parseArgs } from './generic-transformers';
 
 describe('SAVE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SAVE.transformArguments(),
+      parseArgs(SAVE),
       ['SAVE']
     );
   });
diff --git a/packages/client/lib/commands/SAVE.ts b/packages/client/lib/commands/SAVE.ts
index ee6cccd35a0..dbf3ec343bf 100644
--- a/packages/client/lib/commands/SAVE.ts
+++ b/packages/client/lib/commands/SAVE.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['SAVE'];
+  parseCommand(parser: CommandParser) {
+    parser.push('SAVE');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCAN.spec.ts b/packages/client/lib/commands/SCAN.spec.ts
index f4dd865d113..2a32cbebf4f 100644
--- a/packages/client/lib/commands/SCAN.spec.ts
+++ b/packages/client/lib/commands/SCAN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import SCAN from './SCAN';
 
 describe('SCAN', () => {
   describe('transformArguments', () => {
     it('cusror only', () => {
       assert.deepEqual(
-        SCAN.transformArguments('0'),
+        parseArgs(SCAN, '0'),
         ['SCAN', '0']
       );
     });
 
     it('with MATCH', () => {
       assert.deepEqual(
-        SCAN.transformArguments('0', {
+        parseArgs(SCAN, '0', {
           MATCH: 'pattern'
         }),
         ['SCAN', '0', 'MATCH', 'pattern']
@@ -22,7 +23,7 @@ describe('SCAN', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        SCAN.transformArguments('0', {
+        parseArgs(SCAN, '0', {
           COUNT: 1
         }),
         ['SCAN', '0', 'COUNT', '1']
@@ -31,7 +32,7 @@ describe('SCAN', () => {
 
     it('with TYPE', () => {
       assert.deepEqual(
-        SCAN.transformArguments('0', {
+        parseArgs(SCAN, '0', {
           TYPE: 'stream'
         }),
         ['SCAN', '0', 'TYPE', 'stream']
@@ -40,7 +41,7 @@ describe('SCAN', () => {
 
     it('with MATCH & COUNT & TYPE', () => {
       assert.deepEqual(
-        SCAN.transformArguments('0', {
+        parseArgs(SCAN, '0', {
           MATCH: 'pattern',
           COUNT: 1,
           TYPE: 'stream'
diff --git a/packages/client/lib/commands/SCAN.ts b/packages/client/lib/commands/SCAN.ts
index 13f54440443..107a400ca46 100644
--- a/packages/client/lib/commands/SCAN.ts
+++ b/packages/client/lib/commands/SCAN.ts
@@ -1,10 +1,26 @@
 import { RedisArgument, CommandArguments, BlobStringReply, ArrayReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface ScanCommonOptions {
   MATCH?: string;
   COUNT?: number;
 }
 
+export function parseScanArguments(
+  parser: CommandParser,
+  cursor: RedisArgument,
+  options?: ScanOptions
+) {
+  parser.push(cursor);
+  if (options?.MATCH) {
+    parser.pushVariadic(['MATCH', options.MATCH]);
+  }
+
+  if (options?.COUNT) {
+    parser.pushVariadic(['COUNT', options.COUNT.toString()]);
+  }
+}
+
 export function pushScanArguments(
   args: CommandArguments,
   cursor: RedisArgument,
@@ -30,15 +46,15 @@ export interface ScanOptions extends ScanCommonOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(cursor: RedisArgument, options?: ScanOptions) {
-    const args = pushScanArguments(['SCAN'], cursor, options);
+  parseCommand(parser: CommandParser, cursor: RedisArgument, options?: ScanOptions) {
+    parser.push('SCAN');
+    parseScanArguments(parser, cursor, options);
 
     if (options?.TYPE) {
-      args.push('TYPE', options.TYPE);
+      parser.pushVariadic(['TYPE', options.TYPE]);
     }
-
-    return args;
   },
+  transformArguments(cursor: RedisArgument, options?: ScanOptions) { return [] },
   transformReply([cursor, keys]: [BlobStringReply, ArrayReply<BlobStringReply>]) {
     return {
       cursor,
diff --git a/packages/client/lib/commands/SCARD.spec.ts b/packages/client/lib/commands/SCARD.spec.ts
index 5029f340d96..53434583832 100644
--- a/packages/client/lib/commands/SCARD.spec.ts
+++ b/packages/client/lib/commands/SCARD.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import SCARD from './SCARD';
 
 describe('SCARD', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SCARD.transformArguments('key'),
+      parseArgs(SCARD, 'key'),
       ['SCARD', 'key']
     );
   });
diff --git a/packages/client/lib/commands/SCARD.ts b/packages/client/lib/commands/SCARD.ts
index c13d042ba60..cc9c8b015e0 100644
--- a/packages/client/lib/commands/SCARD.ts
+++ b/packages/client/lib/commands/SCARD.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['SCARD', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('SCARD');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCRIPT_DEBUG.spec.ts b/packages/client/lib/commands/SCRIPT_DEBUG.spec.ts
index 4e07f2c250c..c98143a3415 100644
--- a/packages/client/lib/commands/SCRIPT_DEBUG.spec.ts
+++ b/packages/client/lib/commands/SCRIPT_DEBUG.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SCRIPT_DEBUG from './SCRIPT_DEBUG';
+import { parseArgs } from './generic-transformers';
 
 describe('SCRIPT DEBUG', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SCRIPT_DEBUG.transformArguments('NO'),
+      parseArgs(SCRIPT_DEBUG, 'NO'),
       ['SCRIPT', 'DEBUG', 'NO']
     );
   });
diff --git a/packages/client/lib/commands/SCRIPT_DEBUG.ts b/packages/client/lib/commands/SCRIPT_DEBUG.ts
index 3c49ff709d5..aa7d93acae3 100644
--- a/packages/client/lib/commands/SCRIPT_DEBUG.ts
+++ b/packages/client/lib/commands/SCRIPT_DEBUG.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(mode: 'YES' | 'SYNC' | 'NO') {
-    return ['SCRIPT', 'DEBUG', mode];
+  parseCommand(parser: CommandParser, mode: 'YES' | 'SYNC' | 'NO') {
+    parser.pushVariadic(['SCRIPT', 'DEBUG', mode]);
   },
+  transformArguments(mode: 'YES' | 'SYNC' | 'NO') { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCRIPT_EXISTS.spec.ts b/packages/client/lib/commands/SCRIPT_EXISTS.spec.ts
index 8afdbb5f581..cf65156c72d 100644
--- a/packages/client/lib/commands/SCRIPT_EXISTS.spec.ts
+++ b/packages/client/lib/commands/SCRIPT_EXISTS.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SCRIPT_EXISTS from './SCRIPT_EXISTS';
+import { parseArgs } from './generic-transformers';
 
 describe('SCRIPT EXISTS', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SCRIPT_EXISTS.transformArguments('sha1'),
+        parseArgs(SCRIPT_EXISTS, 'sha1'),
         ['SCRIPT', 'EXISTS', 'sha1']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SCRIPT_EXISTS.transformArguments(['1', '2']),
+        parseArgs(SCRIPT_EXISTS, ['1', '2']),
         ['SCRIPT', 'EXISTS', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SCRIPT_EXISTS.ts b/packages/client/lib/commands/SCRIPT_EXISTS.ts
index ab0a293d8de..5e4d54ac8d5 100644
--- a/packages/client/lib/commands/SCRIPT_EXISTS.ts
+++ b/packages/client/lib/commands/SCRIPT_EXISTS.ts
@@ -1,11 +1,14 @@
 import { ArrayReply, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(sha1: RedisVariadicArgument) {
-    return pushVariadicArguments(['SCRIPT', 'EXISTS'], sha1);
+  parseCommand(parser: CommandParser, sha1: RedisVariadicArgument) {
+    parser.pushVariadic(['SCRIPT', 'EXISTS']);
+    parser.pushVariadic(sha1);
   },
+  transformArguments(sha1: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<NumberReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCRIPT_FLUSH.spec.ts b/packages/client/lib/commands/SCRIPT_FLUSH.spec.ts
index ccc14ecc285..c51efd1a36c 100644
--- a/packages/client/lib/commands/SCRIPT_FLUSH.spec.ts
+++ b/packages/client/lib/commands/SCRIPT_FLUSH.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SCRIPT_FLUSH from './SCRIPT_FLUSH';
+import { parseArgs } from './generic-transformers';
 
 describe('SCRIPT FLUSH', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SCRIPT_FLUSH.transformArguments(),
+        parseArgs(SCRIPT_FLUSH),
         ['SCRIPT', 'FLUSH']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        SCRIPT_FLUSH.transformArguments('SYNC'),
+        parseArgs(SCRIPT_FLUSH, 'SYNC'),
         ['SCRIPT', 'FLUSH', 'SYNC']
       );
     });
diff --git a/packages/client/lib/commands/SCRIPT_FLUSH.ts b/packages/client/lib/commands/SCRIPT_FLUSH.ts
index f5426395628..e91936efdc1 100644
--- a/packages/client/lib/commands/SCRIPT_FLUSH.ts
+++ b/packages/client/lib/commands/SCRIPT_FLUSH.ts
@@ -1,16 +1,16 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(mode?: 'ASYNC' | 'SYNC') {
-    const args = ['SCRIPT', 'FLUSH'];
+  parseCommand(parser: CommandParser, mode?: 'ASYNC' | 'SYNC') {
+    parser.pushVariadic(['SCRIPT', 'FLUSH']);
 
     if (mode) {
-      args.push(mode);
+      parser.push(mode);
     }
-
-    return args;
   },
+  transformArguments(mode?: 'ASYNC' | 'SYNC') { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCRIPT_KILL.spec.ts b/packages/client/lib/commands/SCRIPT_KILL.spec.ts
index 1499c97ac07..7186efd54cf 100644
--- a/packages/client/lib/commands/SCRIPT_KILL.spec.ts
+++ b/packages/client/lib/commands/SCRIPT_KILL.spec.ts
@@ -1,10 +1,11 @@
 import { strict as assert } from 'node:assert';
 import SCRIPT_KILL from './SCRIPT_KILL';
+import { parseArgs } from './generic-transformers';
 
 describe('SCRIPT KILL', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SCRIPT_KILL.transformArguments(),
+      parseArgs(SCRIPT_KILL),
       ['SCRIPT', 'KILL']
     );
   });
diff --git a/packages/client/lib/commands/SCRIPT_KILL.ts b/packages/client/lib/commands/SCRIPT_KILL.ts
index ac025b788bb..80a7faa3f7c 100644
--- a/packages/client/lib/commands/SCRIPT_KILL.ts
+++ b/packages/client/lib/commands/SCRIPT_KILL.ts
@@ -1,10 +1,12 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['SCRIPT', 'KILL'];
+  parseCommand(parser: CommandParser) {
+    parser.pushVariadic(['SCRIPT', 'KILL']);
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SCRIPT_LOAD.spec.ts b/packages/client/lib/commands/SCRIPT_LOAD.spec.ts
index d964859d2ff..b0df9887e11 100644
--- a/packages/client/lib/commands/SCRIPT_LOAD.spec.ts
+++ b/packages/client/lib/commands/SCRIPT_LOAD.spec.ts
@@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SCRIPT_LOAD from './SCRIPT_LOAD';
 import { scriptSha1 } from '../lua-script';
+import { parseArgs } from './generic-transformers';
 
 describe('SCRIPT LOAD', () => {
   const SCRIPT = 'return 1;',
@@ -9,7 +10,7 @@ describe('SCRIPT LOAD', () => {
 
   it('transformArguments', () => {
     assert.deepEqual(
-      SCRIPT_LOAD.transformArguments(SCRIPT),
+      parseArgs(SCRIPT_LOAD, SCRIPT),
       ['SCRIPT', 'LOAD', SCRIPT]
     );
   });
diff --git a/packages/client/lib/commands/SCRIPT_LOAD.ts b/packages/client/lib/commands/SCRIPT_LOAD.ts
index 90028b13a5f..4efac44f888 100644
--- a/packages/client/lib/commands/SCRIPT_LOAD.ts
+++ b/packages/client/lib/commands/SCRIPT_LOAD.ts
@@ -1,10 +1,12 @@
 import { BlobStringReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(script: RedisArgument) {
-    return ['SCRIPT', 'LOAD', script];
+  parseCommand(parser: CommandParser, script: RedisArgument) {
+    parser.pushVariadic(['SCRIPT', 'LOAD', script]);
   },
+  transformArguments(script: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SDIFF.spec.ts b/packages/client/lib/commands/SDIFF.spec.ts
index 83ac6dc1da1..a943a80688d 100644
--- a/packages/client/lib/commands/SDIFF.spec.ts
+++ b/packages/client/lib/commands/SDIFF.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SDIFF from './SDIFF';
+import { parseArgs } from './generic-transformers';
 
 describe('SDIFF', () => {
-  describe('transformArguments', () => {
+  describe('processCommand', () => {
     it('string', () => {
       assert.deepEqual(
-        SDIFF.transformArguments('key'),
+        parseArgs(SDIFF, 'key'),
         ['SDIFF', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SDIFF.transformArguments(['1', '2']),
+        parseArgs(SDIFF, ['1', '2']),
         ['SDIFF', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SDIFF.ts b/packages/client/lib/commands/SDIFF.ts
index 918cbf7fa15..82ada635ffb 100644
--- a/packages/client/lib/commands/SDIFF.ts
+++ b/packages/client/lib/commands/SDIFF.ts
@@ -1,11 +1,15 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['SDIFF'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('SDIFF');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SDIFFSTORE.spec.ts b/packages/client/lib/commands/SDIFFSTORE.spec.ts
index 613a9eb590b..43213adfbb0 100644
--- a/packages/client/lib/commands/SDIFFSTORE.spec.ts
+++ b/packages/client/lib/commands/SDIFFSTORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SDIFFSTORE from './SDIFFSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('SDIFFSTORE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SDIFFSTORE.transformArguments('destination', 'key'),
+        parseArgs(SDIFFSTORE, 'destination', 'key'),
         ['SDIFFSTORE', 'destination', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SDIFFSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(SDIFFSTORE, 'destination', ['1', '2']),
         ['SDIFFSTORE', 'destination', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SDIFFSTORE.ts b/packages/client/lib/commands/SDIFFSTORE.ts
index 15f0ccb499a..a9eef0ffaf4 100644
--- a/packages/client/lib/commands/SDIFFSTORE.ts
+++ b/packages/client/lib/commands/SDIFFSTORE.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['SDIFFSTORE', destination], keys);
+  parseCommand(parser: CommandParser, destination: RedisArgument, keys: RedisVariadicArgument) {
+    parser.push('SDIFFSTORE');
+    parser.pushKey(destination);
+    parser.pushKeys(keys);
   },
+  transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SET.spec.ts b/packages/client/lib/commands/SET.spec.ts
index 4364eb7391a..b8aa57fe77b 100644
--- a/packages/client/lib/commands/SET.spec.ts
+++ b/packages/client/lib/commands/SET.spec.ts
@@ -1,20 +1,21 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SET from './SET';
+import { parseArgs } from './generic-transformers';
 
 describe('SET', () => {
   describe('transformArguments', () => {
     describe('value', () => {
       it('string', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value'),
+          parseArgs(SET, 'key', 'value'),
           ['SET', 'key', 'value']
         );
       });
   
       it('number', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 0),
+          parseArgs(SET, 'key', 0),
           ['SET', 'key', '0']
         );
       });
@@ -23,7 +24,7 @@ describe('SET', () => {
     describe('expiration', () => {
       it('\'KEEPTTL\'', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             expiration: 'KEEPTTL'
           }),
           ['SET', 'key', 'value', 'KEEPTTL']
@@ -32,7 +33,7 @@ describe('SET', () => {
 
       it('{ type: \'KEEPTTL\' }', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             expiration: {
               type: 'KEEPTTL'
             }
@@ -43,7 +44,7 @@ describe('SET', () => {
 
       it('{ type: \'EX\' }', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             expiration: {
               type: 'EX',
               value: 0
@@ -55,7 +56,7 @@ describe('SET', () => {
 
       it('with EX (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             EX: 0
           }),
           ['SET', 'key', 'value', 'EX', '0']
@@ -64,7 +65,7 @@ describe('SET', () => {
 
       it('with PX (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             PX: 0
           }),
           ['SET', 'key', 'value', 'PX', '0']
@@ -73,7 +74,7 @@ describe('SET', () => {
 
       it('with EXAT (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             EXAT: 0
           }),
           ['SET', 'key', 'value', 'EXAT', '0']
@@ -82,7 +83,7 @@ describe('SET', () => {
 
       it('with PXAT (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             PXAT: 0
           }),
           ['SET', 'key', 'value', 'PXAT', '0']
@@ -91,7 +92,7 @@ describe('SET', () => {
 
       it('with KEEPTTL (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             KEEPTTL: true
           }),
           ['SET', 'key', 'value', 'KEEPTTL']
@@ -102,7 +103,7 @@ describe('SET', () => {
     describe('condition', () => {
       it('with condition', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             condition: 'NX'
           }),
           ['SET', 'key', 'value', 'NX']
@@ -111,7 +112,7 @@ describe('SET', () => {
 
       it('with NX (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             NX: true
           }),
           ['SET', 'key', 'value', 'NX']
@@ -120,7 +121,7 @@ describe('SET', () => {
 
       it('with XX (backwards compatibility)', () => {
         assert.deepEqual(
-          SET.transformArguments('key', 'value', {
+          parseArgs(SET, 'key', 'value', {
             XX: true
           }),
           ['SET', 'key', 'value', 'XX']
@@ -130,7 +131,7 @@ describe('SET', () => {
 
     it('with GET', () => {
       assert.deepEqual(
-        SET.transformArguments('key', 'value', {
+        parseArgs(SET, 'key', 'value', {
           GET: true
         }),
         ['SET', 'key', 'value', 'GET']
@@ -139,7 +140,7 @@ describe('SET', () => {
 
     it('with expiration, condition, GET', () => {
       assert.deepEqual(
-        SET.transformArguments('key', 'value', {
+        parseArgs(SET, 'key', 'value', {
           expiration: {
             type: 'EX',
             value: 0 
diff --git a/packages/client/lib/commands/SET.ts b/packages/client/lib/commands/SET.ts
index cede62e7055..138889a6e9a 100644
--- a/packages/client/lib/commands/SET.ts
+++ b/packages/client/lib/commands/SET.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface SetOptions {
   expiration?: {
@@ -43,49 +44,48 @@ export interface SetOptions {
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, value: RedisArgument | number, options?: SetOptions) {
-    const args = [
-      'SET',
-      key,
-      typeof value === 'number' ? value.toString() : value
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument | number, options?: SetOptions) {
+    parser.push('SET');
+    parser.pushKey(key);
+    parser.push(typeof value === 'number' ? value.toString() : value);
 
     if (options?.expiration) {
       if (typeof options.expiration === 'string') {
-        args.push(options.expiration);
+        parser.push(options.expiration);
       } else if (options.expiration.type === 'KEEPTTL') {
-        args.push('KEEPTTL');
+        parser.push('KEEPTTL');
       } else {
-        args.push(
-          options.expiration.type,
-          options.expiration.value.toString()
+        parser.pushVariadic(
+          [
+            options.expiration.type,
+            options.expiration.value.toString()
+          ]
         );
       }
     } else if (options?.EX !== undefined) {
-      args.push('EX', options.EX.toString());
+      parser.pushVariadic(['EX', options.EX.toString()]);
     } else if (options?.PX !== undefined) {
-      args.push('PX', options.PX.toString());
+      parser.pushVariadic(['PX', options.PX.toString()]);
     } else if (options?.EXAT !== undefined) {
-      args.push('EXAT', options.EXAT.toString());
+      parser.pushVariadic(['EXAT', options.EXAT.toString()]);
     } else if (options?.PXAT !== undefined) {
-      args.push('PXAT', options.PXAT.toString());
+      parser.pushVariadic(['PXAT', options.PXAT.toString()]);
     } else if (options?.KEEPTTL) {
-      args.push('KEEPTTL');
+      parser.push('KEEPTTL');
     }
 
     if (options?.condition) {
-      args.push(options.condition);
+      parser.push(options.condition);
     } else if (options?.NX) {
-      args.push('NX');
+      parser.push('NX');
     } else if (options?.XX) {
-      args.push('XX');
+      parser.push('XX');
     }
 
     if (options?.GET) {
-      args.push('GET');
+      parser.push('GET');
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, value: RedisArgument | number, options?: SetOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'> | BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SETBIT.spec.ts b/packages/client/lib/commands/SETBIT.spec.ts
index e4470bb1528..1eedcc69959 100644
--- a/packages/client/lib/commands/SETBIT.spec.ts
+++ b/packages/client/lib/commands/SETBIT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SETBIT from './SETBIT';
+import { parseArgs } from './generic-transformers';
 
 describe('SETBIT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SETBIT.transformArguments('key', 0, 1),
+      parseArgs(SETBIT, 'key', 0, 1),
       ['SETBIT', 'key', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/SETBIT.ts b/packages/client/lib/commands/SETBIT.ts
index 5b3ec6173dc..26dbd2cfaff 100644
--- a/packages/client/lib/commands/SETBIT.ts
+++ b/packages/client/lib/commands/SETBIT.ts
@@ -1,15 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { BitValue } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    key: RedisArgument,
-    offset: number,
-    value: BitValue
-  ) {
-    return ['SETBIT', key, offset.toString(), value.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, offset: number, value: BitValue) {
+    parser.push('SETBIT');
+    parser.pushKey(key);
+    parser.pushVariadic([offset.toString(), value.toString()]);
   },
+  transformArguments(key: RedisArgument, offset: number, value: BitValue) { return [] },
   transformReply: undefined as unknown as () => NumberReply<BitValue>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SETEX.spec.ts b/packages/client/lib/commands/SETEX.spec.ts
index 00f204cc713..7bc934ccd68 100644
--- a/packages/client/lib/commands/SETEX.spec.ts
+++ b/packages/client/lib/commands/SETEX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SETEX from './SETEX';
+import { parseArgs } from './generic-transformers';
 
 describe('SETEX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SETEX.transformArguments('key', 1, 'value'),
+      parseArgs(SETEX, 'key', 1, 'value'),
       ['SETEX', 'key', '1', 'value']
     );
   });
diff --git a/packages/client/lib/commands/SETEX.ts b/packages/client/lib/commands/SETEX.ts
index bbd77e5d990..523d1d5a6c7 100644
--- a/packages/client/lib/commands/SETEX.ts
+++ b/packages/client/lib/commands/SETEX.ts
@@ -1,18 +1,13 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    seconds: number,
-    value: RedisArgument
-  ) {
-    return [
-      'SETEX',
-      key,
-      seconds.toString(),
-      value
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, seconds: number, value: RedisArgument) {
+    parser.push('SETEX');
+    parser.pushKey(key);
+    parser.pushVariadic([seconds.toString(), value]);
   },
+  transformArguments(key: RedisArgument, seconds: number, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SETNX .spec.ts b/packages/client/lib/commands/SETNX .spec.ts
index 5cfca29ba62..81a5af3d411 100644
--- a/packages/client/lib/commands/SETNX .spec.ts	
+++ b/packages/client/lib/commands/SETNX .spec.ts	
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SETNX from './SETNX';
+import { parseArgs } from './generic-transformers';
 
 describe('SETNX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SETNX.transformArguments('key', 'value'),
+      parseArgs(SETNX, 'key', 'value'),
       ['SETNX', 'key', 'value']
     );
   });
diff --git a/packages/client/lib/commands/SETNX.ts b/packages/client/lib/commands/SETNX.ts
index 0940efad693..7b429f60c1e 100644
--- a/packages/client/lib/commands/SETNX.ts
+++ b/packages/client/lib/commands/SETNX.ts
@@ -1,9 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(key: RedisArgument, value: RedisArgument) {
-    return ['SETNX', key, value];
+  parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) {
+    parser.push('SETNX');
+    parser.pushKey(key);
+    parser.push(value);
   },
+  transformArguments(key: RedisArgument, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SETRANGE.spec.ts b/packages/client/lib/commands/SETRANGE.spec.ts
index 01d3545a359..acdab5bcd3b 100644
--- a/packages/client/lib/commands/SETRANGE.spec.ts
+++ b/packages/client/lib/commands/SETRANGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SETRANGE from './SETRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('SETRANGE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SETRANGE.transformArguments('key', 0, 'value'),
+      parseArgs(SETRANGE, 'key', 0, 'value'),
       ['SETRANGE', 'key', '0', 'value']
     );
   });
diff --git a/packages/client/lib/commands/SETRANGE.ts b/packages/client/lib/commands/SETRANGE.ts
index 1951a82c07d..01ba83e6a06 100644
--- a/packages/client/lib/commands/SETRANGE.ts
+++ b/packages/client/lib/commands/SETRANGE.ts
@@ -1,18 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
-    key: RedisArgument,
-    offset: number,
-    value: RedisArgument
-  ) {
-    return [
-      'SETRANGE',
-      key,
-      offset.toString(),
-      value
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, offset: number, value: RedisArgument) {
+    parser.push('SETRANGE');
+    parser.pushKey(key);
+    parser.pushVariadic([offset.toString(), value]);
   },
+  transformArguments(key: RedisArgument, offset: number, value: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SHUTDOWN.spec.ts b/packages/client/lib/commands/SHUTDOWN.spec.ts
index 7dd46a5d534..9c4ca852ad3 100644
--- a/packages/client/lib/commands/SHUTDOWN.spec.ts
+++ b/packages/client/lib/commands/SHUTDOWN.spec.ts
@@ -1,18 +1,19 @@
 import { strict as assert } from 'node:assert';
 import SHUTDOWN from './SHUTDOWN';
+import { parseArgs } from './generic-transformers';
 
 describe('SHUTDOWN', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SHUTDOWN.transformArguments(),
+        parseArgs(SHUTDOWN),
         ['SHUTDOWN']
       );
     });
 
     it('with mode', () => {
       assert.deepEqual(
-        SHUTDOWN.transformArguments({
+        parseArgs(SHUTDOWN, {
           mode: 'NOSAVE'
         }),
         ['SHUTDOWN', 'NOSAVE']
@@ -21,7 +22,7 @@ describe('SHUTDOWN', () => {
 
     it('with NOW', () => {
       assert.deepEqual(
-        SHUTDOWN.transformArguments({
+        parseArgs(SHUTDOWN, {
           NOW: true
         }),
         ['SHUTDOWN', 'NOW']
@@ -30,7 +31,7 @@ describe('SHUTDOWN', () => {
 
     it('with FORCE', () => {
       assert.deepEqual(
-        SHUTDOWN.transformArguments({
+        parseArgs(SHUTDOWN, {
           FORCE: true
         }),
         ['SHUTDOWN', 'FORCE']
@@ -39,7 +40,7 @@ describe('SHUTDOWN', () => {
 
     it('with ABORT', () => {
       assert.deepEqual(
-        SHUTDOWN.transformArguments({
+        parseArgs(SHUTDOWN, {
           ABORT: true
         }),
         ['SHUTDOWN', 'ABORT']
diff --git a/packages/client/lib/commands/SHUTDOWN.ts b/packages/client/lib/commands/SHUTDOWN.ts
index e0f3d08ce81..3098277b8f2 100644
--- a/packages/client/lib/commands/SHUTDOWN.ts
+++ b/packages/client/lib/commands/SHUTDOWN.ts
@@ -1,4 +1,5 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface ShutdownOptions {
   mode?: 'NOSAVE' | 'SAVE';
@@ -10,26 +11,25 @@ export interface ShutdownOptions {
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(options?: ShutdownOptions) {
-    const args = ['SHUTDOWN']
+  parseCommand(parser: CommandParser, options?: ShutdownOptions) {
+    parser.push('SHUTDOWN');
 
     if (options?.mode) {
-      args.push(options.mode);
+      parser.push(options.mode);
     }
 
     if (options?.NOW) {
-      args.push('NOW');
+      parser.push('NOW');
     }
 
     if (options?.FORCE) {
-      args.push('FORCE');
+      parser.push('FORCE');
     }
 
     if (options?.ABORT) {
-      args.push('ABORT');
+      parser.push('ABORT');
     }
-
-    return args;
   },
+  transformArguments(options?: ShutdownOptions) { return [] },
   transformReply: undefined as unknown as () => void | SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SINTER.spec.ts b/packages/client/lib/commands/SINTER.spec.ts
index 5b66fdd3f89..6ca7b959ca7 100644
--- a/packages/client/lib/commands/SINTER.spec.ts
+++ b/packages/client/lib/commands/SINTER.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SINTER from './SINTER';
+import { parseArgs } from './generic-transformers';
 
 describe('SINTER', () => {
-  describe('transformArguments', () => {
+  describe('processCommand', () => {
     it('string', () => {
       assert.deepEqual(
-        SINTER.transformArguments('key'),
+        parseArgs(SINTER, 'key'),
         ['SINTER', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SINTER.transformArguments(['1', '2']),
+        parseArgs(SINTER, ['1', '2']),
         ['SINTER', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SINTER.ts b/packages/client/lib/commands/SINTER.ts
index f3f27de2e38..168db707169 100644
--- a/packages/client/lib/commands/SINTER.ts
+++ b/packages/client/lib/commands/SINTER.ts
@@ -1,11 +1,15 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['SINTER'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('SINTER');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SINTERCARD.spec.ts b/packages/client/lib/commands/SINTERCARD.spec.ts
index cddb886088a..51aed13415d 100644
--- a/packages/client/lib/commands/SINTERCARD.spec.ts
+++ b/packages/client/lib/commands/SINTERCARD.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SINTERCARD from './SINTERCARD';
+import { parseArgs } from './generic-transformers';
 
 describe('SINTERCARD', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,21 +9,21 @@ describe('SINTERCARD', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SINTERCARD.transformArguments(['1', '2']),
+        parseArgs(SINTERCARD, ['1', '2']),
         ['SINTERCARD', '2', '1', '2']
       );
     });
 
     it('with limit (backwards compatibility)', () => {
       assert.deepEqual(
-        SINTERCARD.transformArguments(['1', '2'], 1),
+        parseArgs(SINTERCARD, ['1', '2'], 1),
         ['SINTERCARD', '2', '1', '2', 'LIMIT', '1']
       );
     });
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        SINTERCARD.transformArguments(['1', '2'], {
+        parseArgs(SINTERCARD, ['1', '2'], {
           LIMIT: 1
         }),
         ['SINTERCARD', '2', '1', '2', 'LIMIT', '1']
diff --git a/packages/client/lib/commands/SINTERCARD.ts b/packages/client/lib/commands/SINTERCARD.ts
index 626bc1048c3..611bf2e9e25 100644
--- a/packages/client/lib/commands/SINTERCARD.ts
+++ b/packages/client/lib/commands/SINTERCARD.ts
@@ -1,5 +1,6 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export interface SInterCardOptions {
   LIMIT?: number;
@@ -8,19 +9,17 @@ export interface SInterCardOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
-    keys: RedisVariadicArgument,
-    options?: SInterCardOptions | number // `number` for backwards compatibility
-  ) {
-    const args = pushVariadicArgument(['SINTERCARD'], keys);
+  // option `number` for backwards compatibility
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument, options?: SInterCardOptions | number) {
+    parser.push('SINTERCARD');
+    parser.pushKeysLength(keys);
 
     if (typeof options === 'number') { // backwards compatibility
-      args.push('LIMIT', options.toString());
+      parser.pushVariadic(['LIMIT', options.toString()]);
     } else if (options?.LIMIT !== undefined) {
-      args.push('LIMIT', options.LIMIT.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.toString()]);
     }
-
-    return args;
   },
+  transformArguments(keys: RedisVariadicArgument, options?: SInterCardOptions | number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SINTERSTORE.spec.ts b/packages/client/lib/commands/SINTERSTORE.spec.ts
index 05416742ee9..83302a5c829 100644
--- a/packages/client/lib/commands/SINTERSTORE.spec.ts
+++ b/packages/client/lib/commands/SINTERSTORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SINTERSTORE from './SINTERSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('SINTERSTORE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SINTERSTORE.transformArguments('destination', 'key'),
+        parseArgs(SINTERSTORE, 'destination', 'key'),
         ['SINTERSTORE', 'destination', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SINTERSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(SINTERSTORE, 'destination', ['1', '2']),
         ['SINTERSTORE', 'destination', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SINTERSTORE.ts b/packages/client/lib/commands/SINTERSTORE.ts
index 744e0b18456..982cddeeefd 100644
--- a/packages/client/lib/commands/SINTERSTORE.ts
+++ b/packages/client/lib/commands/SINTERSTORE.ts
@@ -1,14 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    destination: RedisArgument,
-    keys: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['SINTERSTORE', destination], keys);
+  parseCommand(parser: CommandParser, destination: RedisArgument, keys: RedisVariadicArgument) {
+    parser.push('SINTERSTORE');
+    parser.pushKey(destination)
+    parser.pushKeys(keys);
   },
+  transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SISMEMBER.spec.ts b/packages/client/lib/commands/SISMEMBER.spec.ts
index 0c1b92614cb..4796475c52c 100644
--- a/packages/client/lib/commands/SISMEMBER.spec.ts
+++ b/packages/client/lib/commands/SISMEMBER.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SISMEMBER from './SISMEMBER';
+import { parseArgs } from './generic-transformers';
 
 describe('SISMEMBER', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      SISMEMBER.transformArguments('key', 'member'),
+      parseArgs(SISMEMBER, 'key', 'member'),
       ['SISMEMBER', 'key', 'member']
     );
   });
diff --git a/packages/client/lib/commands/SISMEMBER.ts b/packages/client/lib/commands/SISMEMBER.ts
index 0687d19de30..0f80d2e93bd 100644
--- a/packages/client/lib/commands/SISMEMBER.ts
+++ b/packages/client/lib/commands/SISMEMBER.ts
@@ -1,10 +1,15 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, member: RedisArgument) {
-    return ['SISMEMBER', key, member];
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisArgument) {
+    parser.setCachable();
+    parser.push('SISMEMBER');
+    parser.pushKey(key);
+    parser.push(member);
   },
+  transformArguments(key: RedisArgument, member: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SMEMBERS.spec.ts b/packages/client/lib/commands/SMEMBERS.spec.ts
index 016b01ff747..6e2582e5abc 100644
--- a/packages/client/lib/commands/SMEMBERS.spec.ts
+++ b/packages/client/lib/commands/SMEMBERS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SMEMBERS from './SMEMBERS';
+import { parseArgs } from './generic-transformers';
 
 describe('SMEMBERS', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      SMEMBERS.transformArguments('key'),
+      parseArgs(SMEMBERS, 'key'),
       ['SMEMBERS', 'key']
     );
   });
diff --git a/packages/client/lib/commands/SMEMBERS.ts b/packages/client/lib/commands/SMEMBERS.ts
index 391c83af6c6..b57b7a3fd97 100644
--- a/packages/client/lib/commands/SMEMBERS.ts
+++ b/packages/client/lib/commands/SMEMBERS.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, ArrayReply, BlobStringReply, SetReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['SMEMBERS', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('SMEMBERS');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: {
     2: undefined as unknown as () => ArrayReply<BlobStringReply>,
     3: undefined as unknown as () => SetReply<BlobStringReply>
diff --git a/packages/client/lib/commands/SMISMEMBER.spec.ts b/packages/client/lib/commands/SMISMEMBER.spec.ts
index 273ab05dd75..deff6912360 100644
--- a/packages/client/lib/commands/SMISMEMBER.spec.ts
+++ b/packages/client/lib/commands/SMISMEMBER.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SMISMEMBER from './SMISMEMBER';
+import { parseArgs } from './generic-transformers';
 
 describe('SMISMEMBER', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      SMISMEMBER.transformArguments('key', ['1', '2']),
+      parseArgs(SMISMEMBER, 'key', ['1', '2']),
       ['SMISMEMBER', 'key', '1', '2']
     );
   });
diff --git a/packages/client/lib/commands/SMISMEMBER.ts b/packages/client/lib/commands/SMISMEMBER.ts
index bdf48d45ab4..26e633e2b33 100644
--- a/packages/client/lib/commands/SMISMEMBER.ts
+++ b/packages/client/lib/commands/SMISMEMBER.ts
@@ -1,10 +1,17 @@
 import { RedisArgument, ArrayReply, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, members: Array<RedisArgument>) {
-    return ['SMISMEMBER', key, ...members];
+  parseCommand(parser: CommandParser, key: RedisArgument, members: Array<RedisArgument>) {
+    parser.setCachable();
+    parser.push('SMISMEMBER');
+    parser.pushKey(key);
+    for (const member of members) {
+      parser.push(member);
+    }
   },
+  transformArguments(key: RedisArgument, members: Array<RedisArgument>) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<NumberReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SMOVE.spec.ts b/packages/client/lib/commands/SMOVE.spec.ts
index 7ff2f773a7b..c68a6e41914 100644
--- a/packages/client/lib/commands/SMOVE.spec.ts
+++ b/packages/client/lib/commands/SMOVE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SMOVE from './SMOVE';
+import { parseArgs } from './generic-transformers';
 
 describe('SMOVE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SMOVE.transformArguments('source', 'destination', 'member'),
+      parseArgs(SMOVE, 'source', 'destination', 'member'),
       ['SMOVE', 'source', 'destination', 'member']
     );
   });
diff --git a/packages/client/lib/commands/SMOVE.ts b/packages/client/lib/commands/SMOVE.ts
index 183b363fb90..baca87bf07f 100644
--- a/packages/client/lib/commands/SMOVE.ts
+++ b/packages/client/lib/commands/SMOVE.ts
@@ -1,14 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    source: RedisArgument,
-    destination: RedisArgument,
-    member: RedisArgument
-  ) {
-    return ['SMOVE', source, destination, member];
+  parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument, member: RedisArgument) {
+    parser.push('SMOVE');
+    parser.pushKeys([source, destination]);
+    parser.push(member);
   },
+  transformArguments(source: RedisArgument, destination: RedisArgument, member: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SORT.spec.ts b/packages/client/lib/commands/SORT.spec.ts
index 4fce8113755..330b321a1b8 100644
--- a/packages/client/lib/commands/SORT.spec.ts
+++ b/packages/client/lib/commands/SORT.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SORT from './SORT';
+import { parseArgs } from './generic-transformers';
 
 describe('SORT', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SORT.transformArguments('key'),
+        parseArgs(SORT, 'key'),
         ['SORT', 'key']
       );
     });
 
     it('with BY', () => {
       assert.deepEqual(
-        SORT.transformArguments('key', {
+        parseArgs(SORT, 'key', {
           BY: 'pattern'
         }),
         ['SORT', 'key', 'BY', 'pattern']
@@ -22,7 +23,7 @@ describe('SORT', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        SORT.transformArguments('key', {
+        parseArgs(SORT, 'key', {
           LIMIT: {
             offset: 0,
             count: 1
@@ -35,7 +36,7 @@ describe('SORT', () => {
     describe('with GET', () => {
       it('string', () => {
         assert.deepEqual(
-          SORT.transformArguments('key', {
+          parseArgs(SORT, 'key', {
             GET: 'pattern'
           }),
           ['SORT', 'key', 'GET', 'pattern']
@@ -44,7 +45,7 @@ describe('SORT', () => {
 
       it('array', () => {
         assert.deepEqual(
-          SORT.transformArguments('key', {
+          parseArgs(SORT, 'key', {
             GET: ['1', '2']
           }),
           ['SORT', 'key', 'GET', '1', 'GET', '2']
@@ -54,7 +55,7 @@ describe('SORT', () => {
 
     it('with DIRECTION', () => {
       assert.deepEqual(
-        SORT.transformArguments('key', {
+        parseArgs(SORT, 'key', {
           DIRECTION: 'ASC'
         }),
         ['SORT', 'key', 'ASC']
@@ -63,7 +64,7 @@ describe('SORT', () => {
 
     it('with ALPHA', () => {
       assert.deepEqual(
-        SORT.transformArguments('key', {
+        parseArgs(SORT, 'key', {
           ALPHA: true
         }),
         ['SORT', 'key', 'ALPHA']
@@ -72,7 +73,7 @@ describe('SORT', () => {
 
     it('with BY, LIMIT, GET, DIRECTION, ALPHA', () => {
       assert.deepEqual(
-        SORT.transformArguments('key', {
+        parseArgs(SORT, 'key', {
           BY: 'pattern',
           LIMIT: {
             offset: 0,
diff --git a/packages/client/lib/commands/SORT.ts b/packages/client/lib/commands/SORT.ts
index b71383943e9..0ea89590746 100644
--- a/packages/client/lib/commands/SORT.ts
+++ b/packages/client/lib/commands/SORT.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface SortOptions {
   BY?: RedisArgument;
@@ -11,49 +12,58 @@ export interface SortOptions {
   ALPHA?: boolean;
 }
 
-export function transformSortArguments(
+export function parseSortArguments(
   command: RedisArgument,
+  parser: CommandParser,
   key: RedisArgument,
   options?: SortOptions
 ) {
-  const args: Array<RedisArgument> = [command, key];
+  parser.push(command);
+  parser.pushKey(key);
 
   if (options?.BY) {
-    args.push('BY', options.BY);
+    parser.pushVariadic(['BY', options.BY]);
   }
 
   if (options?.LIMIT) {
-    args.push(
-      'LIMIT',
-      options.LIMIT.offset.toString(),
-      options.LIMIT.count.toString()
+    parser.pushVariadic(
+      [
+        'LIMIT',
+        options.LIMIT.offset.toString(),
+        options.LIMIT.count.toString()
+      ]
     );
   }
 
   if (options?.GET) {
     if (Array.isArray(options.GET)) {
       for (const pattern of options.GET) {
-        args.push('GET', pattern);
+        parser.pushVariadic(['GET', pattern]);
       }
     } else {
-      args.push('GET', options.GET);
+      parser.pushVariadic(['GET', options.GET]);
     }
   }
 
   if (options?.DIRECTION) {
-    args.push(options.DIRECTION);
+    parser.push(options.DIRECTION);
   }
 
   if (options?.ALPHA) {
-    args.push('ALPHA');
+    parser.push('ALPHA');
   }
-
-  return args;
 }
 
+export function transformSortArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  options?: SortOptions
+) { return [] }
+
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand: parseSortArguments.bind(undefined, 'SORT'),
   transformArguments: transformSortArguments.bind(undefined, 'SORT'),
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SORT_RO.spec.ts b/packages/client/lib/commands/SORT_RO.spec.ts
index 963416ae639..86f8e507033 100644
--- a/packages/client/lib/commands/SORT_RO.spec.ts
+++ b/packages/client/lib/commands/SORT_RO.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SORT_RO from './SORT_RO';
+import { parseArgs } from './generic-transformers';
 
 describe('SORT_RO', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('SORT_RO', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key'),
+        parseArgs(SORT_RO, 'key'),
         ['SORT_RO', 'key']
       );
     });
 
     it('with BY', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key', {
+        parseArgs(SORT_RO, 'key', {
           BY: 'pattern'
         }),
         ['SORT_RO', 'key', 'BY', 'pattern']
@@ -24,7 +25,7 @@ describe('SORT_RO', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key', {
+        parseArgs(SORT_RO, 'key', {
           LIMIT: {
             offset: 0,
             count: 1
@@ -37,7 +38,7 @@ describe('SORT_RO', () => {
     describe('with GET', () => {
       it('string', () => {
         assert.deepEqual(
-          SORT_RO.transformArguments('key', {
+          parseArgs(SORT_RO, 'key', {
             GET: 'pattern'
           }),
           ['SORT_RO', 'key', 'GET', 'pattern']
@@ -46,7 +47,7 @@ describe('SORT_RO', () => {
 
       it('array', () => {
         assert.deepEqual(
-          SORT_RO.transformArguments('key', {
+          parseArgs(SORT_RO, 'key', {
             GET: ['1', '2']
           }),
           ['SORT_RO', 'key', 'GET', '1', 'GET', '2']
@@ -56,7 +57,7 @@ describe('SORT_RO', () => {
 
     it('with DIRECTION', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key', {
+        parseArgs(SORT_RO, 'key', {
           DIRECTION: 'ASC'
         }),
         ['SORT_RO', 'key', 'ASC']
@@ -65,7 +66,7 @@ describe('SORT_RO', () => {
 
     it('with ALPHA', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key', {
+        parseArgs(SORT_RO, 'key', {
           ALPHA: true
         }),
         ['SORT_RO', 'key', 'ALPHA']
@@ -74,7 +75,7 @@ describe('SORT_RO', () => {
 
     it('with BY, LIMIT, GET, DIRECTION, ALPHA', () => {
       assert.deepEqual(
-        SORT_RO.transformArguments('key', {
+        parseArgs(SORT_RO, 'key', {
           BY: 'pattern',
           LIMIT: {
             offset: 0,
diff --git a/packages/client/lib/commands/SORT_RO.ts b/packages/client/lib/commands/SORT_RO.ts
index 459a0bbc03d..7520af2d66e 100644
--- a/packages/client/lib/commands/SORT_RO.ts
+++ b/packages/client/lib/commands/SORT_RO.ts
@@ -1,9 +1,10 @@
 import { Command } from '../RESP/types';
-import SORT, { transformSortArguments } from './SORT';
+import SORT, { parseSortArguments, transformSortArguments } from './SORT';
 
 export default {
   FIRST_KEY_INDEX: SORT.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
+  parseCommand: parseSortArguments.bind(undefined, 'SORT_RO'),
   transformArguments: transformSortArguments.bind(undefined, 'SORT_RO'),
   transformReply: SORT.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SORT_STORE.spec.ts b/packages/client/lib/commands/SORT_STORE.spec.ts
index 49efd4c6ad8..a812cec52c5 100644
--- a/packages/client/lib/commands/SORT_STORE.spec.ts
+++ b/packages/client/lib/commands/SORT_STORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SORT_STORE from './SORT_STORE';
+import { parseArgs } from './generic-transformers';
 
 describe('SORT STORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination'),
+        parseArgs(SORT_STORE, 'source', 'destination'),
         ['SORT', 'source', 'STORE', 'destination']
       );
     });
 
     it('with BY', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination', {
+        parseArgs(SORT_STORE, 'source', 'destination', {
           BY: 'pattern'
         }),
         ['SORT', 'source', 'BY', 'pattern', 'STORE', 'destination']
@@ -22,7 +23,7 @@ describe('SORT STORE', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination', {
+        parseArgs(SORT_STORE, 'source', 'destination', {
           LIMIT: {
             offset: 0,
             count: 1
@@ -35,7 +36,7 @@ describe('SORT STORE', () => {
     describe('with GET', () => {
       it('string', () => {
         assert.deepEqual(
-          SORT_STORE.transformArguments('source', 'destination', {
+          parseArgs(SORT_STORE, 'source', 'destination', {
             GET: 'pattern'
           }),
           ['SORT', 'source', 'GET', 'pattern', 'STORE', 'destination']
@@ -44,7 +45,7 @@ describe('SORT STORE', () => {
 
       it('array', () => {
         assert.deepEqual(
-          SORT_STORE.transformArguments('source', 'destination', {
+          parseArgs(SORT_STORE, 'source', 'destination', {
             GET: ['1', '2']
           }),
           ['SORT', 'source', 'GET', '1', 'GET', '2', 'STORE', 'destination']
@@ -54,7 +55,7 @@ describe('SORT STORE', () => {
 
     it('with DIRECTION', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination', {
+        parseArgs(SORT_STORE, 'source', 'destination', {
           DIRECTION: 'ASC'
         }),
         ['SORT', 'source', 'ASC', 'STORE', 'destination']
@@ -63,7 +64,7 @@ describe('SORT STORE', () => {
 
     it('with ALPHA', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination', {
+        parseArgs(SORT_STORE, 'source', 'destination', {
           ALPHA: true
         }),
         ['SORT', 'source', 'ALPHA', 'STORE', 'destination']
@@ -72,7 +73,7 @@ describe('SORT STORE', () => {
 
     it('with BY, LIMIT, GET, DIRECTION, ALPHA', () => {
       assert.deepEqual(
-        SORT_STORE.transformArguments('source', 'destination', {
+        parseArgs(SORT_STORE, 'source', 'destination', {
           BY: 'pattern',
           LIMIT: {
             offset: 0,
diff --git a/packages/client/lib/commands/SORT_STORE.ts b/packages/client/lib/commands/SORT_STORE.ts
index b6ad709fb60..26f9139db9d 100644
--- a/packages/client/lib/commands/SORT_STORE.ts
+++ b/packages/client/lib/commands/SORT_STORE.ts
@@ -1,17 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import SORT, { SortOptions } from './SORT';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    source: RedisArgument,
-    destination: RedisArgument,
-    options?: SortOptions
-  ) {
-    const args = SORT.transformArguments(source, options);
-    args.push('STORE', destination);
-    return args;
+  parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument, options?: SortOptions) {
+    SORT.parseCommand(parser, source, options);
+    parser.pushVariadic(['STORE', destination]);
   },
+  transformArguments(source: RedisArgument, destination: RedisArgument, options?: SortOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SPOP.spec.ts b/packages/client/lib/commands/SPOP.spec.ts
index 896c1c820ac..f435134416b 100644
--- a/packages/client/lib/commands/SPOP.spec.ts
+++ b/packages/client/lib/commands/SPOP.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SPOP from './SPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('SPOP', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SPOP.transformArguments('key'),
+      parseArgs(SPOP, 'key'),
       ['SPOP', 'key']
     );
   });
diff --git a/packages/client/lib/commands/SPOP.ts b/packages/client/lib/commands/SPOP.ts
index 4b061a86306..03e69fe1a64 100644
--- a/packages/client/lib/commands/SPOP.ts
+++ b/packages/client/lib/commands/SPOP.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument) {
-    return ['SPOP', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('SPOP');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SPOP_COUNT.spec.ts b/packages/client/lib/commands/SPOP_COUNT.spec.ts
index ddad816b420..935ff437800 100644
--- a/packages/client/lib/commands/SPOP_COUNT.spec.ts
+++ b/packages/client/lib/commands/SPOP_COUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SPOP_COUNT from './SPOP_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('SPOP_COUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SPOP_COUNT.transformArguments('key', 1),
+      parseArgs(SPOP_COUNT, 'key', 1),
       ['SPOP', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/SPOP_COUNT.ts b/packages/client/lib/commands/SPOP_COUNT.ts
index 4c68ae8d08e..0faa21d61f2 100644
--- a/packages/client/lib/commands/SPOP_COUNT.ts
+++ b/packages/client/lib/commands/SPOP_COUNT.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['SPOP', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('SPOP');
+    parser.pushKey(key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SPUBLISH.spec.ts b/packages/client/lib/commands/SPUBLISH.spec.ts
index 741372d0154..5a53bc40b7d 100644
--- a/packages/client/lib/commands/SPUBLISH.spec.ts
+++ b/packages/client/lib/commands/SPUBLISH.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SPUBLISH from './SPUBLISH';
+import { parseArgs } from './generic-transformers';
 
 describe('SPUBLISH', () => {
   testUtils.isVersionGreaterThanHook([7]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      SPUBLISH.transformArguments('channel', 'message'),
+      parseArgs(SPUBLISH, 'channel', 'message'),
       ['SPUBLISH', 'channel', 'message']
     );
   });
diff --git a/packages/client/lib/commands/SPUBLISH.ts b/packages/client/lib/commands/SPUBLISH.ts
index 19d84b03c6f..9755bb79d51 100644
--- a/packages/client/lib/commands/SPUBLISH.ts
+++ b/packages/client/lib/commands/SPUBLISH.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(channel: RedisArgument, message: RedisArgument) {
-    return ['SPUBLISH', channel, message];
+  parseCommand(parser: CommandParser, channel: RedisArgument, message: RedisArgument) {
+    parser.push('SPUBLISH');
+    parser.pushKey(channel);
+    parser.push(message);
   },
+  transformArguments(channel: RedisArgument, message: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SRANDMEMBER.spec.ts b/packages/client/lib/commands/SRANDMEMBER.spec.ts
index a7df01f0eb9..637aac27b29 100644
--- a/packages/client/lib/commands/SRANDMEMBER.spec.ts
+++ b/packages/client/lib/commands/SRANDMEMBER.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SRANDMEMBER from './SRANDMEMBER';
+import { parseArgs } from './generic-transformers';
 
 describe('SRANDMEMBER', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SRANDMEMBER.transformArguments('key'),
+      parseArgs(SRANDMEMBER, 'key'),
       ['SRANDMEMBER', 'key']
     );
   });
diff --git a/packages/client/lib/commands/SRANDMEMBER.ts b/packages/client/lib/commands/SRANDMEMBER.ts
index 6a2373ae927..bc9d2568234 100644
--- a/packages/client/lib/commands/SRANDMEMBER.ts
+++ b/packages/client/lib/commands/SRANDMEMBER.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['SRANDMEMBER', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('SRANDMEMBER')
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SRANDMEMBER_COUNT.spec.ts b/packages/client/lib/commands/SRANDMEMBER_COUNT.spec.ts
index 364eb640341..13bb0d52d96 100644
--- a/packages/client/lib/commands/SRANDMEMBER_COUNT.spec.ts
+++ b/packages/client/lib/commands/SRANDMEMBER_COUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SRANDMEMBER_COUNT from './SRANDMEMBER_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('SRANDMEMBER COUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SRANDMEMBER_COUNT.transformArguments('key', 1),
+      parseArgs(SRANDMEMBER_COUNT, 'key', 1),
       ['SRANDMEMBER', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/SRANDMEMBER_COUNT.ts b/packages/client/lib/commands/SRANDMEMBER_COUNT.ts
index 778f3d8f629..df9f5e3fc68 100644
--- a/packages/client/lib/commands/SRANDMEMBER_COUNT.ts
+++ b/packages/client/lib/commands/SRANDMEMBER_COUNT.ts
@@ -1,13 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import SRANDMEMBER from './SRANDMEMBER';
 
 export default {
   FIRST_KEY_INDEX: SRANDMEMBER.FIRST_KEY_INDEX,
   IS_READ_ONLY: SRANDMEMBER.IS_READ_ONLY,
-  transformArguments(key: RedisArgument, count: number) {
-    const args = SRANDMEMBER.transformArguments(key);
-    args.push(count.toString());
-    return args;
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    SRANDMEMBER.parseCommand(parser, key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SREM.spec.ts b/packages/client/lib/commands/SREM.spec.ts
index f17c6fb118e..6def4178fc8 100644
--- a/packages/client/lib/commands/SREM.spec.ts
+++ b/packages/client/lib/commands/SREM.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SREM from './SREM';
+import { parseArgs } from './generic-transformers';
 
 describe('SREM', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SREM.transformArguments('key', 'member'),
+        parseArgs(SREM, 'key', 'member'),
         ['SREM', 'key', 'member']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SREM.transformArguments('key', ['1', '2']),
+        parseArgs(SREM, 'key', ['1', '2']),
         ['SREM', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SREM.ts b/packages/client/lib/commands/SREM.ts
index daa95493d02..d576d2ee119 100644
--- a/packages/client/lib/commands/SREM.ts
+++ b/packages/client/lib/commands/SREM.ts
@@ -1,11 +1,15 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, members: RedisVariadicArgument) {
-    return pushVariadicArguments(['SREM', key], members);
+  parseCommand(parser: CommandParser, key: RedisArgument, members: RedisVariadicArgument) {
+    parser.push('SREM');
+    parser.pushKey(key);
+    parser.pushVariadic(members);
   },
+  transformArguments(key: RedisArgument, members: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SSCAN.spec.ts b/packages/client/lib/commands/SSCAN.spec.ts
index 29a13306fde..e5d689c6e98 100644
--- a/packages/client/lib/commands/SSCAN.spec.ts
+++ b/packages/client/lib/commands/SSCAN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SSCAN from './SSCAN';
+import { parseArgs } from './generic-transformers';
 
 describe('SSCAN', () => {
   describe('transformArguments', () => {
     it('cusror only', () => {
       assert.deepEqual(
-        SSCAN.transformArguments('key', '0'),
+        parseArgs(SSCAN, 'key', '0'),
         ['SSCAN', 'key', '0']
       );
     });
 
     it('with MATCH', () => {
       assert.deepEqual(
-        SSCAN.transformArguments('key', '0', {
+        parseArgs(SSCAN, 'key', '0', {
           MATCH: 'pattern'
         }),
         ['SSCAN', 'key', '0', 'MATCH', 'pattern']
@@ -22,7 +23,7 @@ describe('SSCAN', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        SSCAN.transformArguments('key', '0', {
+        parseArgs(SSCAN, 'key', '0', {
           COUNT: 1
         }),
         ['SSCAN', 'key', '0', 'COUNT', '1']
@@ -31,7 +32,7 @@ describe('SSCAN', () => {
 
     it('with MATCH & COUNT', () => {
       assert.deepEqual(
-        SSCAN.transformArguments('key', '0', {
+        parseArgs(SSCAN, 'key', '0', {
           MATCH: 'pattern',
           COUNT: 1
         }),
diff --git a/packages/client/lib/commands/SSCAN.ts b/packages/client/lib/commands/SSCAN.ts
index f47144d834c..e0d8ea9a2e4 100644
--- a/packages/client/lib/commands/SSCAN.ts
+++ b/packages/client/lib/commands/SSCAN.ts
@@ -1,16 +1,25 @@
 import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
-import { ScanCommonOptions, pushScanArguments } from './SCAN';
+import { CommandParser } from '../client/parser';
+import { ScanCommonOptions, parseScanArguments} from './SCAN';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     cursor: RedisArgument,
     options?: ScanCommonOptions
   ) {
-    return pushScanArguments(['SSCAN', key], cursor, options);
+    parser.push('SSCAN');
+    parser.pushKey(key);
+    parseScanArguments(parser, cursor, options);
   },
+  transformArguments(
+    key: RedisArgument,
+    cursor: RedisArgument,
+    options?: ScanCommonOptions
+  ) { return [] },
   transformReply([cursor, members]: [BlobStringReply, Array<BlobStringReply>]) {
     return {
       cursor,
diff --git a/packages/client/lib/commands/STRLEN.spec.ts b/packages/client/lib/commands/STRLEN.spec.ts
index b07c07b909a..dbb7a08541b 100644
--- a/packages/client/lib/commands/STRLEN.spec.ts
+++ b/packages/client/lib/commands/STRLEN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import STRLEN from './STRLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('STRLEN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      STRLEN.transformArguments('key'),
+      parseArgs(STRLEN, 'key'),
       ['STRLEN', 'key']
     );
   });
diff --git a/packages/client/lib/commands/STRLEN.ts b/packages/client/lib/commands/STRLEN.ts
index 594530ff6bf..8ce5f1eadb5 100644
--- a/packages/client/lib/commands/STRLEN.ts
+++ b/packages/client/lib/commands/STRLEN.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['STRLEN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable()
+    parser.push('STRLEN');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SUNION.spec.ts b/packages/client/lib/commands/SUNION.spec.ts
index ff00c44a1b1..a4389d4236e 100644
--- a/packages/client/lib/commands/SUNION.spec.ts
+++ b/packages/client/lib/commands/SUNION.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SUNION from './SUNION';
+import { parseArgs } from './generic-transformers';
 
 describe('SUNION', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SUNION.transformArguments('key'),
+        parseArgs(SUNION, 'key'),
         ['SUNION', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SUNION.transformArguments(['1', '2']),
+        parseArgs(SUNION, ['1', '2']),
         ['SUNION', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SUNION.ts b/packages/client/lib/commands/SUNION.ts
index 42042217e2b..ab13bafc415 100644
--- a/packages/client/lib/commands/SUNION.ts
+++ b/packages/client/lib/commands/SUNION.ts
@@ -1,11 +1,15 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArguments(['SUNION'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('SUNION');
+    parser.pushKeys(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SUNIONSTORE.spec.ts b/packages/client/lib/commands/SUNIONSTORE.spec.ts
index 790fd78060a..8f3db2cacd7 100644
--- a/packages/client/lib/commands/SUNIONSTORE.spec.ts
+++ b/packages/client/lib/commands/SUNIONSTORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SUNIONSTORE from './SUNIONSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('SUNIONSTORE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        SUNIONSTORE.transformArguments('destination', 'key'),
+        parseArgs(SUNIONSTORE, 'destination', 'key'),
         ['SUNIONSTORE', 'destination', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        SUNIONSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(SUNIONSTORE, 'destination', ['1', '2']),
         ['SUNIONSTORE', 'destination', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/SUNIONSTORE.ts b/packages/client/lib/commands/SUNIONSTORE.ts
index 9adaa9288f3..787ba535de6 100644
--- a/packages/client/lib/commands/SUNIONSTORE.ts
+++ b/packages/client/lib/commands/SUNIONSTORE.ts
@@ -1,14 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    destination: RedisArgument,
-    keys: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['SUNIONSTORE', destination], keys);
+  parseCommand(parser: CommandParser, destination: RedisArgument, keys: RedisVariadicArgument) {
+    parser.push('SUNIONSTORE');
+    parser.pushKey(destination);
+    parser.pushKeys(keys);
   },
+  transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/SWAPDB.spec.ts b/packages/client/lib/commands/SWAPDB.spec.ts
index 9331854c13b..a3b53b27218 100644
--- a/packages/client/lib/commands/SWAPDB.spec.ts
+++ b/packages/client/lib/commands/SWAPDB.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SWAPDB from './SWAPDB';
+import { parseArgs } from './generic-transformers';
 
 describe('SWAPDB', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SWAPDB.transformArguments(0, 1),
+      parseArgs(SWAPDB, 0, 1),
       ['SWAPDB', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/SWAPDB.ts b/packages/client/lib/commands/SWAPDB.ts
index f3b768e95f4..3fc5e4291de 100644
--- a/packages/client/lib/commands/SWAPDB.ts
+++ b/packages/client/lib/commands/SWAPDB.ts
@@ -1,11 +1,13 @@
 import { SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(index1: number, index2: number) {
-    return ['SWAPDB', index1.toString(), index2.toString()];
+  parseCommand(parser: CommandParser, index1: number, index2: number) {
+    parser.pushVariadic(['SWAPDB', index1.toString(), index2.toString()]);
   },
+  transformArguments(index1: number, index2: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/TIME.spec.ts b/packages/client/lib/commands/TIME.spec.ts
index d9dd9667ea4..4ee704f0dd0 100644
--- a/packages/client/lib/commands/TIME.spec.ts
+++ b/packages/client/lib/commands/TIME.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TIME from './TIME';
+import { parseArgs } from './generic-transformers';
 
 describe('TIME', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      TIME.transformArguments(),
+      parseArgs(TIME),
       ['TIME']
     );
   });
diff --git a/packages/client/lib/commands/TIME.ts b/packages/client/lib/commands/TIME.ts
index d4dc67ae483..f4df4a439fa 100644
--- a/packages/client/lib/commands/TIME.ts
+++ b/packages/client/lib/commands/TIME.ts
@@ -1,11 +1,13 @@
 import { BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['TIME'];
+  parseCommand(parser: CommandParser) {
+    parser.push('TIME');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => [
     unixTimestamp: BlobStringReply<`${number}`>,
     microseconds: BlobStringReply<`${number}`>
diff --git a/packages/client/lib/commands/TOUCH.spec.ts b/packages/client/lib/commands/TOUCH.spec.ts
index 48e77900ee3..69a3498346b 100644
--- a/packages/client/lib/commands/TOUCH.spec.ts
+++ b/packages/client/lib/commands/TOUCH.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TOUCH from './TOUCH';
+import { parseArgs } from './generic-transformers';
 
 describe('TOUCH', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        TOUCH.transformArguments('key'),
+        parseArgs(TOUCH, 'key'),
         ['TOUCH', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        TOUCH.transformArguments(['1', '2']),
+        parseArgs(TOUCH, ['1', '2']),
         ['TOUCH', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/TOUCH.ts b/packages/client/lib/commands/TOUCH.ts
index c1c19402f8b..3a4a92440c5 100644
--- a/packages/client/lib/commands/TOUCH.ts
+++ b/packages/client/lib/commands/TOUCH.ts
@@ -1,11 +1,14 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisVariadicArgument) {
-    return pushVariadicArguments(['TOUCH'], key);
+  parseCommand(parser: CommandParser, key: RedisVariadicArgument) {
+    parser.push('TOUCH');
+    parser.pushKeys(key);
   },
+  transformArguments(key: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/TTL.spec.ts b/packages/client/lib/commands/TTL.spec.ts
index 6b709226a2b..4d36053c02e 100644
--- a/packages/client/lib/commands/TTL.spec.ts
+++ b/packages/client/lib/commands/TTL.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TTL from './TTL';
+import { parseArgs } from './generic-transformers';
 
 describe('TTL', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      TTL.transformArguments('key'),
+      parseArgs(TTL, 'key'),
       ['TTL', 'key']
     );
   });
diff --git a/packages/client/lib/commands/TTL.ts b/packages/client/lib/commands/TTL.ts
index 65c3b7b026f..4617f28ed71 100644
--- a/packages/client/lib/commands/TTL.ts
+++ b/packages/client/lib/commands/TTL.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['TTL', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('TTL');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/TYPE.spec.ts b/packages/client/lib/commands/TYPE.spec.ts
index 45cf1cfc1c9..ae7392cdce9 100644
--- a/packages/client/lib/commands/TYPE.spec.ts
+++ b/packages/client/lib/commands/TYPE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TYPE from './TYPE';
+import { parseArgs } from './generic-transformers';
 
 describe('TYPE', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      TYPE.transformArguments('key'),
+      parseArgs(TYPE, 'key'),
       ['TYPE', 'key']
     );
   });
diff --git a/packages/client/lib/commands/TYPE.ts b/packages/client/lib/commands/TYPE.ts
index 09f6887492c..8a0cd2076fe 100644
--- a/packages/client/lib/commands/TYPE.ts
+++ b/packages/client/lib/commands/TYPE.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['TYPE', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('TYPE');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/UNLINK.spec.ts b/packages/client/lib/commands/UNLINK.spec.ts
index 1e374783007..2c32bee8e33 100644
--- a/packages/client/lib/commands/UNLINK.spec.ts
+++ b/packages/client/lib/commands/UNLINK.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import UNLINK from './UNLINK';
+import { parseArgs } from './generic-transformers';
 
 describe('UNLINK', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        UNLINK.transformArguments('key'),
+        parseArgs(UNLINK, 'key'),
         ['UNLINK', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        UNLINK.transformArguments(['1', '2']),
+        parseArgs(UNLINK, ['1', '2']),
         ['UNLINK', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/UNLINK.ts b/packages/client/lib/commands/UNLINK.ts
index 2346573f397..077bb872af3 100644
--- a/packages/client/lib/commands/UNLINK.ts
+++ b/packages/client/lib/commands/UNLINK.ts
@@ -1,11 +1,14 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisVariadicArgument) {
-    return pushVariadicArguments(['UNLINK'], key);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.push('UNLINK');
+    parser.pushVariadic(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/WAIT.spec.ts b/packages/client/lib/commands/WAIT.spec.ts
index 61b197c90ba..d2778e7967b 100644
--- a/packages/client/lib/commands/WAIT.spec.ts
+++ b/packages/client/lib/commands/WAIT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import WAIT from './WAIT';
+import { parseArgs } from './generic-transformers';
 
 describe('WAIT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      WAIT.transformArguments(0, 1),
+      parseArgs(WAIT, 0, 1),
       ['WAIT', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/WAIT.ts b/packages/client/lib/commands/WAIT.ts
index 21c39a643e5..fae475f81c9 100644
--- a/packages/client/lib/commands/WAIT.ts
+++ b/packages/client/lib/commands/WAIT.ts
@@ -1,10 +1,12 @@
 import { NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(numberOfReplicas: number, timeout: number) {
-    return ['WAIT', numberOfReplicas.toString(), timeout.toString()];
+  parseCommand(parser: CommandParser, numberOfReplicas: number, timeout: number) {
+    parser.pushVariadic(['WAIT', numberOfReplicas.toString(), timeout.toString()]);
   },
+  transformArguments(numberOfReplicas: number, timeout: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XACK.spec.ts b/packages/client/lib/commands/XACK.spec.ts
index 81a7954ffd6..4ad60b256d0 100644
--- a/packages/client/lib/commands/XACK.spec.ts
+++ b/packages/client/lib/commands/XACK.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XACK from './XACK';
+import { parseArgs } from './generic-transformers';
 
 describe('XACK', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        XACK.transformArguments('key', 'group', '0-0'),
+        parseArgs(XACK, 'key', 'group', '0-0'),
         ['XACK', 'key', 'group', '0-0']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        XACK.transformArguments('key', 'group', ['0-0', '1-0']),
+        parseArgs(XACK, 'key', 'group', ['0-0', '1-0']),
         ['XACK', 'key', 'group', '0-0', '1-0']
       );
     });
diff --git a/packages/client/lib/commands/XACK.ts b/packages/client/lib/commands/XACK.ts
index 89b2d581201..15e500f15ae 100644
--- a/packages/client/lib/commands/XACK.ts
+++ b/packages/client/lib/commands/XACK.ts
@@ -1,15 +1,17 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
-    key: RedisArgument,
-    group: RedisArgument,
-    id: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['XACK', key, group], id);
+  parseCommand(parser: CommandParser, key: RedisArgument, group: RedisArgument, id: RedisVariadicArgument) {
+    parser.push('XACK');
+    parser.pushKey(key);
+    parser.push(group)
+    parser.pushVariadic(id);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument, id: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
+ 
\ No newline at end of file
diff --git a/packages/client/lib/commands/XADD.spec.ts b/packages/client/lib/commands/XADD.spec.ts
index 10c6f4daa56..321581d0865 100644
--- a/packages/client/lib/commands/XADD.spec.ts
+++ b/packages/client/lib/commands/XADD.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XADD from './XADD';
+import { parseArgs } from './generic-transformers';
 
 describe('XADD', () => {
   describe('transformArguments', () => {
     it('single field', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           field: 'value'
         }),
         ['XADD', 'key', '*', 'field', 'value']
@@ -15,7 +16,7 @@ describe('XADD', () => {
 
     it('multiple fields', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           '1': 'I',
           '2': 'II'
         }),
@@ -25,7 +26,7 @@ describe('XADD', () => {
 
     it('with TRIM', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -38,7 +39,7 @@ describe('XADD', () => {
 
     it('with TRIM.strategy', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -52,7 +53,7 @@ describe('XADD', () => {
 
     it('with TRIM.strategyModifier', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -66,7 +67,7 @@ describe('XADD', () => {
 
     it('with TRIM.limit', () => {
       assert.deepEqual(
-        XADD.transformArguments('key', '*', {
+        parseArgs(XADD, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
diff --git a/packages/client/lib/commands/XADD.ts b/packages/client/lib/commands/XADD.ts
index b681069c729..b8d23137b1a 100644
--- a/packages/client/lib/commands/XADD.ts
+++ b/packages/client/lib/commands/XADD.ts
@@ -1,4 +1,5 @@
-import { RedisArgument, BlobStringReply, Command, CommandArguments } from '../RESP/types';
+import { RedisArgument, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XAddOptions {
   TRIM?: {
@@ -9,47 +10,52 @@ export interface XAddOptions {
   };
 }
 
-export function pushXAddArguments(
-  args: CommandArguments,
+export function parseXAddArguments(
+  optional: RedisArgument | undefined,
+  parser: CommandParser,
+  key: RedisArgument,
   id: RedisArgument,
   message: Record<string, RedisArgument>,
   options?: XAddOptions
 ) {
+  parser.push('XADD');
+  parser.pushKey(key);
+  if (optional) {
+    parser.push(optional);
+  }
+
   if (options?.TRIM) {
     if (options.TRIM.strategy) {
-      args.push(options.TRIM.strategy);
+      parser.push(options.TRIM.strategy);
     }
 
     if (options.TRIM.strategyModifier) {
-      args.push(options.TRIM.strategyModifier);
+      parser.push(options.TRIM.strategyModifier);
     }
 
-    args.push(options.TRIM.threshold.toString());
+    parser.push(options.TRIM.threshold.toString());
 
     if (options.TRIM.limit) {
-      args.push('LIMIT', options.TRIM.limit.toString());
+      parser.pushVariadic(['LIMIT', options.TRIM.limit.toString()]);
     }
   }
 
-  args.push(id);
+  parser.push(id);
 
   for (const [key, value] of Object.entries(message)) {
-    args.push(key, value);
+    parser.pushVariadic([key, value]);
   }
-
-  return args;
 }
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
+  parseCommand: parseXAddArguments.bind(undefined, undefined),
   transformArguments(
     key: RedisArgument,
     id: RedisArgument,
     message: Record<string, RedisArgument>,
     options?: XAddOptions
-  ) {
-    return pushXAddArguments(['XADD', key], id, message, options);
-  },
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts b/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts
index a3dd5602a3b..97927f212ff 100644
--- a/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts
+++ b/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XADD_NOMKSTREAM from './XADD_NOMKSTREAM';
+import { parseArgs } from './generic-transformers';
 
 describe('XADD NOMKSTREAM', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,7 +9,7 @@ describe('XADD NOMKSTREAM', () => {
   describe('transformArguments', () => {
     it('single field', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           field: 'value'
         }),
         ['XADD', 'key', 'NOMKSTREAM', '*', 'field', 'value']
@@ -17,7 +18,7 @@ describe('XADD NOMKSTREAM', () => {
 
     it('multiple fields', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           '1': 'I',
           '2': 'II'
         }),
@@ -27,7 +28,7 @@ describe('XADD NOMKSTREAM', () => {
 
     it('with TRIM', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -40,7 +41,7 @@ describe('XADD NOMKSTREAM', () => {
 
     it('with TRIM.strategy', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -54,7 +55,7 @@ describe('XADD NOMKSTREAM', () => {
 
     it('with TRIM.strategyModifier', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
@@ -68,7 +69,7 @@ describe('XADD NOMKSTREAM', () => {
 
     it('with TRIM.limit', () => {
       assert.deepEqual(
-        XADD_NOMKSTREAM.transformArguments('key', '*', {
+        parseArgs(XADD_NOMKSTREAM, 'key', '*', {
           field: 'value'
         }, {
           TRIM: {
diff --git a/packages/client/lib/commands/XADD_NOMKSTREAM.ts b/packages/client/lib/commands/XADD_NOMKSTREAM.ts
index 65e7dd566e3..c1067050ba3 100644
--- a/packages/client/lib/commands/XADD_NOMKSTREAM.ts
+++ b/packages/client/lib/commands/XADD_NOMKSTREAM.ts
@@ -1,16 +1,15 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
-import { XAddOptions, pushXAddArguments } from './XADD';
+import { XAddOptions, parseXAddArguments } from './XADD';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
+  parseCommand: parseXAddArguments.bind(undefined, 'NOMKSTREAM'),
   transformArguments(
     key: RedisArgument,
     id: RedisArgument,
     message: Record<string, RedisArgument>,
     options?: XAddOptions
-  ) {
-    return pushXAddArguments(['XADD', key, 'NOMKSTREAM'], id, message, options);
-  },
+  ) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XAUTOCLAIM.spec.ts b/packages/client/lib/commands/XAUTOCLAIM.spec.ts
index 256c58cc4d6..58b09a63e78 100644
--- a/packages/client/lib/commands/XAUTOCLAIM.spec.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XAUTOCLAIM from './XAUTOCLAIM';
+import { parseArgs } from './generic-transformers';
 
 describe('XAUTOCLAIM', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('XAUTOCLAIM', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XAUTOCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0'),
+        parseArgs(XAUTOCLAIM, 'key', 'group', 'consumer', 1, '0-0'),
         ['XAUTOCLAIM', 'key', 'group', 'consumer', '1', '0-0']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        XAUTOCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XAUTOCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           COUNT: 1
         }),
         ['XAUTOCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'COUNT', '1']
diff --git a/packages/client/lib/commands/XAUTOCLAIM.ts b/packages/client/lib/commands/XAUTOCLAIM.ts
index 57ad010991d..14926b4c3ec 100644
--- a/packages/client/lib/commands/XAUTOCLAIM.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesReply, BlobStringReply, ArrayReply, NullReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { StreamMessageReply, transformStreamMessageNullReply } from './generic-transformers';
 
 export interface XAutoClaimOptions {
@@ -14,7 +15,8 @@ export type XAutoClaimRawReply = TuplesReply<[
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     consumer: RedisArgument,
@@ -22,21 +24,22 @@ export default {
     start: RedisArgument,
     options?: XAutoClaimOptions
   ) {
-    const args = [
-      'XAUTOCLAIM',
-      key,
-      group,
-      consumer,
-      minIdleTime.toString(),
-      start
-    ];
+    parser.push('XAUTOCLAIM');
+    parser.pushKey(key);
+    parser.pushVariadic([group, consumer, minIdleTime.toString(), start]);
 
     if (options?.COUNT) {
-      args.push('COUNT', options.COUNT.toString());
+      parser.pushVariadic(['COUNT', options.COUNT.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    group: RedisArgument,
+    consumer: RedisArgument,
+    minIdleTime: number,
+    start: RedisArgument,
+    options?: XAutoClaimOptions
+  ) { return [] },
   transformReply(reply: UnwrapReply<XAutoClaimRawReply>) {
     return {
       nextId: reply[0],
diff --git a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.spec.ts b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.spec.ts
index 96ceb1d8116..78911657086 100644
--- a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.spec.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XAUTOCLAIM_JUSTID from './XAUTOCLAIM_JUSTID';
+import { parseArgs } from './generic-transformers';
 
 describe('XAUTOCLAIM JUSTID', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      XAUTOCLAIM_JUSTID.transformArguments('key', 'group', 'consumer', 1, '0-0'),
+      parseArgs(XAUTOCLAIM_JUSTID, 'key', 'group', 'consumer', 1, '0-0'),
       ['XAUTOCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID']
     );
   });
diff --git a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts
index e2832f23536..045052f9b66 100644
--- a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts
@@ -1,5 +1,7 @@
 import { TuplesReply, BlobStringReply, ArrayReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import XAUTOCLAIM from './XAUTOCLAIM';
+import { Tail } from './generic-transformers';
 
 type XAutoClaimJustIdRawReply = TuplesReply<[
   nextId: BlobStringReply,
@@ -10,11 +12,11 @@ type XAutoClaimJustIdRawReply = TuplesReply<[
 export default {
   FIRST_KEY_INDEX: XAUTOCLAIM.FIRST_KEY_INDEX,
   IS_READ_ONLY: XAUTOCLAIM.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof XAUTOCLAIM.transformArguments>) {
-    const redisArgs = XAUTOCLAIM.transformArguments(...args);
-    redisArgs.push('JUSTID');
-    return redisArgs;
+  parseCommand(parser: CommandParser, ...args: Tail<Parameters<typeof XAUTOCLAIM.parseCommand>>) {
+    XAUTOCLAIM.parseCommand(parser, ...args);
+    parser.push('JUSTID');
   },
+  transformArguments(...args: Parameters<typeof XAUTOCLAIM.transformArguments>) { return [] },
   transformReply(reply: UnwrapReply<XAutoClaimJustIdRawReply>) {
     return {
       nextId: reply[0],
diff --git a/packages/client/lib/commands/XCLAIM.spec.ts b/packages/client/lib/commands/XCLAIM.spec.ts
index e8fde2e1a1a..90768509225 100644
--- a/packages/client/lib/commands/XCLAIM.spec.ts
+++ b/packages/client/lib/commands/XCLAIM.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XCLAIM from './XCLAIM';
+import { parseArgs } from './generic-transformers';
 
 describe('XCLAIM', () => {
   describe('transformArguments', () => {
     it('single id (string)', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0'),
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0'),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0']
       );
     });
 
     it('multiple ids (array)', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, ['0-0', '1-0']),
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, ['0-0', '1-0']),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', '1-0']
       );
     });
 
     it('with IDLE', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           IDLE: 1
         }),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1']
@@ -30,7 +31,7 @@ describe('XCLAIM', () => {
     describe('with TIME', () => {
       it('number', () => {
         assert.deepEqual(
-          XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+          parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
             TIME: 1
           }),
           ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', '1']
@@ -40,7 +41,7 @@ describe('XCLAIM', () => {
       it('Date', () => {
         const d = new Date();
         assert.deepEqual(
-          XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+          parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
             TIME: d
           }),
           ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', d.getTime().toString()]
@@ -50,7 +51,7 @@ describe('XCLAIM', () => {
 
     it('with RETRYCOUNT', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           RETRYCOUNT: 1
         }),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'RETRYCOUNT', '1']
@@ -59,7 +60,7 @@ describe('XCLAIM', () => {
 
     it('with FORCE', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           FORCE: true
         }),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'FORCE']
@@ -68,7 +69,7 @@ describe('XCLAIM', () => {
 
     it('with LASTID', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           LASTID: '0-0'
         }),
         ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'LASTID', '0-0']
@@ -77,7 +78,7 @@ describe('XCLAIM', () => {
 
     it('with IDLE, TIME, RETRYCOUNT, FORCE, LASTID', () => {
       assert.deepEqual(
-        XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
+        parseArgs(XCLAIM, 'key', 'group', 'consumer', 1, '0-0', {
           IDLE: 1,
           TIME: 1,
           RETRYCOUNT: 1,
diff --git a/packages/client/lib/commands/XCLAIM.ts b/packages/client/lib/commands/XCLAIM.ts
index 3ec4f6639ba..ad62e5510ad 100644
--- a/packages/client/lib/commands/XCLAIM.ts
+++ b/packages/client/lib/commands/XCLAIM.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, ArrayReply, NullReply, UnwrapReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments, StreamMessageReply, transformStreamMessageNullReply } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument, StreamMessageReply, transformStreamMessageNullReply } from './generic-transformers';
 
 export interface XClaimOptions {
   IDLE?: number;
@@ -12,7 +13,8 @@ export interface XClaimOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     consumer: RedisArgument,
@@ -20,36 +22,44 @@ export default {
     id: RedisVariadicArgument,
     options?: XClaimOptions
   ) {
-    const args = pushVariadicArguments(
-      ['XCLAIM', key, group, consumer, minIdleTime.toString()],
-      id
-    );
+    parser.push('XCLAIM');
+    parser.pushKey(key);
+    parser.pushVariadic([group, consumer, minIdleTime.toString()]);
+    parser.pushVariadic(id);
 
     if (options?.IDLE !== undefined) {
-      args.push('IDLE', options.IDLE.toString());
+      parser.pushVariadic(['IDLE', options.IDLE.toString()]);
     }
 
     if (options?.TIME !== undefined) {
-      args.push(
-        'TIME',
-        (options.TIME instanceof Date ? options.TIME.getTime() : options.TIME).toString()
+      parser.pushVariadic(
+        [
+          'TIME',
+          (options.TIME instanceof Date ? options.TIME.getTime() : options.TIME).toString()
+        ]
       );
     }
 
     if (options?.RETRYCOUNT !== undefined) {
-      args.push('RETRYCOUNT', options.RETRYCOUNT.toString());
+      parser.pushVariadic(['RETRYCOUNT', options.RETRYCOUNT.toString()]);
     }
 
     if (options?.FORCE) {
-      args.push('FORCE');
+      parser.push('FORCE');
     }
 
     if (options?.LASTID !== undefined) {
-      args.push('LASTID', options.LASTID);
+      parser.pushVariadic(['LASTID', options.LASTID]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    group: RedisArgument,
+    consumer: RedisArgument,
+    minIdleTime: number,
+    id: RedisVariadicArgument,
+    options?: XClaimOptions
+  ) { return [] },
   transformReply(reply: UnwrapReply<ArrayReply<StreamMessageReply | NullReply>>) {
     return reply.map(transformStreamMessageNullReply);
   }
diff --git a/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts b/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts
index 6b580ac3c1b..d7bf9fdc70c 100644
--- a/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts
+++ b/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XCLAIM_JUSTID from './XCLAIM_JUSTID';
+import { parseArgs } from './generic-transformers';
 
 describe('XCLAIM JUSTID', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XCLAIM_JUSTID.transformArguments('key', 'group', 'consumer', 1, '0-0'),
+      parseArgs(XCLAIM_JUSTID, 'key', 'group', 'consumer', 1, '0-0'),
       ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID']
     );
   });
diff --git a/packages/client/lib/commands/XCLAIM_JUSTID.ts b/packages/client/lib/commands/XCLAIM_JUSTID.ts
index 6200c9106e1..4a98c50fff0 100644
--- a/packages/client/lib/commands/XCLAIM_JUSTID.ts
+++ b/packages/client/lib/commands/XCLAIM_JUSTID.ts
@@ -1,13 +1,15 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import XCLAIM from './XCLAIM';
+import { Tail } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: XCLAIM.FIRST_KEY_INDEX,
   IS_READ_ONLY: XCLAIM.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof XCLAIM.transformArguments>) {
-    const redisArgs = XCLAIM.transformArguments(...args);
-    redisArgs.push('JUSTID');
-    return redisArgs;
+  parseCommand(parser: CommandParser, ...args: Tail<Parameters<typeof XCLAIM.parseCommand>>) {
+    XCLAIM.parseCommand(parser, ...args);
+    parser.push('JUSTID');
   },
+  transformArguments(...args: Parameters<typeof XCLAIM.transformArguments>) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XDEL.spec.ts b/packages/client/lib/commands/XDEL.spec.ts
index 15875d3b7b3..510168bb765 100644
--- a/packages/client/lib/commands/XDEL.spec.ts
+++ b/packages/client/lib/commands/XDEL.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XDEL from './XDEL';
+import { parseArgs } from './generic-transformers';
 
 describe('XDEL', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        XDEL.transformArguments('key', '0-0'),
+        parseArgs(XDEL, 'key', '0-0'),
         ['XDEL', 'key', '0-0']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        XDEL.transformArguments('key', ['0-0', '1-0']),
+        parseArgs(XDEL, 'key', ['0-0', '1-0']),
         ['XDEL', 'key', '0-0', '1-0']
       );
     });
diff --git a/packages/client/lib/commands/XDEL.ts b/packages/client/lib/commands/XDEL.ts
index acc9198c2b8..e7572201caa 100644
--- a/packages/client/lib/commands/XDEL.ts
+++ b/packages/client/lib/commands/XDEL.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, id: RedisVariadicArgument) {
-    return pushVariadicArguments(['XDEL', key], id);
+  parseCommand(parser: CommandParser, key: RedisArgument, id: RedisVariadicArgument) {
+    parser.push('XDEL');
+    parser.pushKey(key);
+    parser.pushVariadic(id);
   },
+  transformArguments(key: RedisArgument, id: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XGROUP_CREATE.spec.ts b/packages/client/lib/commands/XGROUP_CREATE.spec.ts
index 5c9071289c9..7c9d6298c6b 100644
--- a/packages/client/lib/commands/XGROUP_CREATE.spec.ts
+++ b/packages/client/lib/commands/XGROUP_CREATE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XGROUP_CREATE from './XGROUP_CREATE';
+import { parseArgs } from './generic-transformers';
 
 describe('XGROUP CREATE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XGROUP_CREATE.transformArguments('key', 'group', '$'),
+        parseArgs(XGROUP_CREATE, 'key', 'group', '$'),
         ['XGROUP', 'CREATE', 'key', 'group', '$']
       );
     });
 
     it('with MKSTREAM', () => {
       assert.deepEqual(
-        XGROUP_CREATE.transformArguments('key', 'group', '$', {
+        parseArgs(XGROUP_CREATE, 'key', 'group', '$', {
           MKSTREAM: true
         }),
         ['XGROUP', 'CREATE', 'key', 'group', '$', 'MKSTREAM']
@@ -22,7 +23,7 @@ describe('XGROUP CREATE', () => {
 
     it('with ENTRIESREAD', () => {
       assert.deepEqual(
-        XGROUP_CREATE.transformArguments('key', 'group', '$', {
+        parseArgs(XGROUP_CREATE, 'key', 'group', '$', {
           ENTRIESREAD: 1
         }),
         ['XGROUP', 'CREATE', 'key', 'group', '$', 'ENTRIESREAD', '1']
diff --git a/packages/client/lib/commands/XGROUP_CREATE.ts b/packages/client/lib/commands/XGROUP_CREATE.ts
index a04fcbeb044..58f9dd9fa40 100644
--- a/packages/client/lib/commands/XGROUP_CREATE.ts
+++ b/packages/client/lib/commands/XGROUP_CREATE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XGroupCreateOptions {
   MKSTREAM?: boolean;
@@ -11,24 +12,31 @@ export interface XGroupCreateOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     id: RedisArgument,
     options?: XGroupCreateOptions
   ) {
-    const args = ['XGROUP', 'CREATE', key, group, id];
+    parser.pushVariadic(['XGROUP', 'CREATE']);
+    parser.pushKey(key);
+    parser.pushVariadic([group, id]);
 
     if (options?.MKSTREAM) {
-      args.push('MKSTREAM');
+      parser.push('MKSTREAM');
     }
 
     if (options?.ENTRIESREAD) {
-      args.push('ENTRIESREAD', options.ENTRIESREAD.toString());
+      parser.pushVariadic(['ENTRIESREAD', options.ENTRIESREAD.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    group: RedisArgument,
+    id: RedisArgument,
+    options?: XGroupCreateOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts b/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts
index 3c3ecbda0a7..eb749073d35 100644
--- a/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts
+++ b/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XGROUP_CREATECONSUMER from './XGROUP_CREATECONSUMER';
+import { parseArgs } from './generic-transformers';
 
 describe('XGROUP CREATECONSUMER', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      XGROUP_CREATECONSUMER.transformArguments('key', 'group', 'consumer'),
+      parseArgs(XGROUP_CREATECONSUMER, 'key', 'group', 'consumer'),
       ['XGROUP', 'CREATECONSUMER', 'key', 'group', 'consumer']
     );
   });
diff --git a/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts b/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts
index 8fd21ca60de..ebe45b54000 100644
--- a/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts
+++ b/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts
@@ -1,14 +1,19 @@
 import { RedisArgument, Command, NumberReply } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     consumer: RedisArgument
   ) {
-    return ['XGROUP', 'CREATECONSUMER', key, group, consumer];
+    parser.pushVariadic(['XGROUP', 'CREATECONSUMER']);
+    parser.pushKey(key);
+    parser.pushVariadic([group, consumer]);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument, consumer: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts b/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts
index afc524eef86..fabef789d78 100644
--- a/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts
+++ b/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XGROUP_DELCONSUMER from './XGROUP_DELCONSUMER';
+import { parseArgs } from './generic-transformers';
 
 describe('XGROUP DELCONSUMER', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XGROUP_DELCONSUMER.transformArguments('key', 'group', 'consumer'),
+      parseArgs(XGROUP_DELCONSUMER, 'key', 'group', 'consumer'),
       ['XGROUP', 'DELCONSUMER', 'key', 'group', 'consumer']
     );
   });
diff --git a/packages/client/lib/commands/XGROUP_DELCONSUMER.ts b/packages/client/lib/commands/XGROUP_DELCONSUMER.ts
index 53007270e05..a7f0f52f059 100644
--- a/packages/client/lib/commands/XGROUP_DELCONSUMER.ts
+++ b/packages/client/lib/commands/XGROUP_DELCONSUMER.ts
@@ -1,14 +1,19 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     consumer: RedisArgument
   ) {
-    return ['XGROUP', 'DELCONSUMER', key, group, consumer];
+    parser.pushVariadic(['XGROUP', 'DELCONSUMER']);
+    parser.pushKey(key);
+    parser.pushVariadic([group, consumer]);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument, consumer: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XGROUP_DESTROY.spec.ts b/packages/client/lib/commands/XGROUP_DESTROY.spec.ts
index 6ec90834518..8277c66d3f6 100644
--- a/packages/client/lib/commands/XGROUP_DESTROY.spec.ts
+++ b/packages/client/lib/commands/XGROUP_DESTROY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XGROUP_DESTROY from './XGROUP_DESTROY';
+import { parseArgs } from './generic-transformers';
 
 describe('XGROUP DESTROY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XGROUP_DESTROY.transformArguments('key', 'group'),
+      parseArgs(XGROUP_DESTROY, 'key', 'group'),
       ['XGROUP', 'DESTROY', 'key', 'group']
     );
   });
diff --git a/packages/client/lib/commands/XGROUP_DESTROY.ts b/packages/client/lib/commands/XGROUP_DESTROY.ts
index 6c14d9ae2bd..3615d7f1743 100644
--- a/packages/client/lib/commands/XGROUP_DESTROY.ts
+++ b/packages/client/lib/commands/XGROUP_DESTROY.ts
@@ -1,13 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
-    key: RedisArgument,
-    group: RedisArgument
-  ) {
-    return ['XGROUP', 'DESTROY', key, group];
+  parseCommand(parser: CommandParser, key: RedisArgument, group: RedisArgument) {
+    parser.pushVariadic(['XGROUP', 'DESTROY']);
+    parser.pushKey(key);
+    parser.push(group);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XGROUP_SETID.spec.ts b/packages/client/lib/commands/XGROUP_SETID.spec.ts
index 891a796d14d..6ea0dd79c37 100644
--- a/packages/client/lib/commands/XGROUP_SETID.spec.ts
+++ b/packages/client/lib/commands/XGROUP_SETID.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XGROUP_SETID from './XGROUP_SETID';
+import { parseArgs } from './generic-transformers';
 
 describe('XGROUP SETID', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XGROUP_SETID.transformArguments('key', 'group', '0'),
+      parseArgs(XGROUP_SETID, 'key', 'group', '0'),
       ['XGROUP', 'SETID', 'key', 'group', '0']
     );
   });
diff --git a/packages/client/lib/commands/XGROUP_SETID.ts b/packages/client/lib/commands/XGROUP_SETID.ts
index a23b4144335..f2330c9b908 100644
--- a/packages/client/lib/commands/XGROUP_SETID.ts
+++ b/packages/client/lib/commands/XGROUP_SETID.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XGroupSetIdOptions {
   /** added in 7.0 */
@@ -8,19 +9,26 @@ export interface XGroupSetIdOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     id: RedisArgument,
     options?: XGroupSetIdOptions
   ) {
-    const args = ['XGROUP', 'SETID', key, group, id];
+    parser.pushVariadic(['XGROUP', 'SETID']);
+    parser.pushKey(key);
+    parser.pushVariadic([group, id]);
 
     if (options?.ENTRIESREAD) {
-      args.push('ENTRIESREAD', options.ENTRIESREAD.toString());
+      parser.pushVariadic(['ENTRIESREAD', options.ENTRIESREAD.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    group: RedisArgument,
+    id: RedisArgument,
+    options?: XGroupSetIdOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
index 86abdbb1493..b1f245dbf18 100644
--- a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
+++ b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XINFO_CONSUMERS from './XINFO_CONSUMERS';
+import { parseArgs } from './generic-transformers';
 
 describe('XINFO CONSUMERS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XINFO_CONSUMERS.transformArguments('key', 'group'),
+      parseArgs(XINFO_CONSUMERS, 'key', 'group'),
       ['XINFO', 'CONSUMERS', 'key', 'group']
     );
   });
diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.ts b/packages/client/lib/commands/XINFO_CONSUMERS.ts
index ca0076d6335..32b8ff95f62 100644
--- a/packages/client/lib/commands/XINFO_CONSUMERS.ts
+++ b/packages/client/lib/commands/XINFO_CONSUMERS.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type XInfoConsumersReply = ArrayReply<TuplesToMapReply<[
   [BlobStringReply<'name'>, BlobStringReply],
@@ -11,12 +12,12 @@ export type XInfoConsumersReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
-    key: RedisArgument,
-    group: RedisArgument
-  ) {
-    return ['XINFO', 'CONSUMERS', key, group];
+  parseCommand(parser: CommandParser, key: RedisArgument, group: RedisArgument) {
+    parser.pushVariadic(['XINFO', 'CONSUMERS']);
+    parser.pushKey(key);
+    parser.push(group);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<XInfoConsumersReply>>) => {
       return reply.map(consumer => {
diff --git a/packages/client/lib/commands/XINFO_GROUPS.spec.ts b/packages/client/lib/commands/XINFO_GROUPS.spec.ts
index 1bee02a0e6d..a1196f4957a 100644
--- a/packages/client/lib/commands/XINFO_GROUPS.spec.ts
+++ b/packages/client/lib/commands/XINFO_GROUPS.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XINFO_GROUPS from './XINFO_GROUPS';
+import { parseArgs } from './generic-transformers';
 
 describe('XINFO GROUPS', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XINFO_GROUPS.transformArguments('key'),
+      parseArgs(XINFO_GROUPS, 'key'),
       ['XINFO', 'GROUPS', 'key']
     );
   });
diff --git a/packages/client/lib/commands/XINFO_GROUPS.ts b/packages/client/lib/commands/XINFO_GROUPS.ts
index 24661ecde84..f17e883d1fd 100644
--- a/packages/client/lib/commands/XINFO_GROUPS.ts
+++ b/packages/client/lib/commands/XINFO_GROUPS.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, NullReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export type XInfoGroupsReply = ArrayReply<TuplesToMapReply<[
   [BlobStringReply<'name'>, BlobStringReply],
@@ -14,9 +15,11 @@ export type XInfoGroupsReply = ArrayReply<TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['XINFO', 'GROUPS', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['XINFO', 'GROUPS']);
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<Resp2Reply<XInfoGroupsReply>>) => {
       return reply.map(group => {
diff --git a/packages/client/lib/commands/XINFO_STREAM.spec.ts b/packages/client/lib/commands/XINFO_STREAM.spec.ts
index 9e6939092e2..7e1829f3059 100644
--- a/packages/client/lib/commands/XINFO_STREAM.spec.ts
+++ b/packages/client/lib/commands/XINFO_STREAM.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XINFO_STREAM from './XINFO_STREAM';
+import { parseArgs } from './generic-transformers';
 
 describe('XINFO STREAM', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      XINFO_STREAM.transformArguments('key'),
+      parseArgs(XINFO_STREAM, 'key'),
       ['XINFO', 'STREAM', 'key']
     );
   });
diff --git a/packages/client/lib/commands/XINFO_STREAM.ts b/packages/client/lib/commands/XINFO_STREAM.ts
index 04721d0ad32..83c889f7daf 100644
--- a/packages/client/lib/commands/XINFO_STREAM.ts
+++ b/packages/client/lib/commands/XINFO_STREAM.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesToMapReply, BlobStringReply, NumberReply, NullReply, TuplesReply, ArrayReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { isNullReply, transformTuplesReply } from './generic-transformers';
 
 export type XInfoStreamReply = TuplesToMapReply<[
@@ -20,9 +21,11 @@ export type XInfoStreamReply = TuplesToMapReply<[
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['XINFO', 'STREAM', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.pushVariadic(['XINFO', 'STREAM']);
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: {
     // TODO: is there a "type safe" way to do it?
     2(reply: any) {
diff --git a/packages/client/lib/commands/XLEN.spec.ts b/packages/client/lib/commands/XLEN.spec.ts
index 164a6d6f094..3e22b9aebfa 100644
--- a/packages/client/lib/commands/XLEN.spec.ts
+++ b/packages/client/lib/commands/XLEN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XLEN from './XLEN';
+import { parseArgs } from './generic-transformers';
 
 describe('XLEN', () => {
-  it('transformArguments', () => {
+  it('processCommand', () => {
     assert.deepEqual(
-      XLEN.transformArguments('key'),
+      parseArgs(XLEN, 'key'),
       ['XLEN', 'key']
     );
   });
diff --git a/packages/client/lib/commands/XLEN.ts b/packages/client/lib/commands/XLEN.ts
index d2ed566a190..47e7d4c098d 100644
--- a/packages/client/lib/commands/XLEN.ts
+++ b/packages/client/lib/commands/XLEN.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['XLEN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('XLEN');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XPENDING.spec.ts b/packages/client/lib/commands/XPENDING.spec.ts
index e6600cce383..55cb957fc62 100644
--- a/packages/client/lib/commands/XPENDING.spec.ts
+++ b/packages/client/lib/commands/XPENDING.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XPENDING from './XPENDING';
+import { parseArgs } from './generic-transformers';
 
 describe('XPENDING', () => {
   describe('transformArguments', () => {
     it('transformArguments', () => {
       assert.deepEqual(
-        XPENDING.transformArguments('key', 'group'),
+        parseArgs(XPENDING, 'key', 'group'),
         ['XPENDING', 'key', 'group']
       );
     });
diff --git a/packages/client/lib/commands/XPENDING.ts b/packages/client/lib/commands/XPENDING.ts
index a6ca4f5a774..3fff74147ab 100644
--- a/packages/client/lib/commands/XPENDING.ts
+++ b/packages/client/lib/commands/XPENDING.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, BlobStringReply, NullReply, ArrayReply, TuplesReply, NumberReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 type XPendingRawReply = TuplesReply<[
   pending: NumberReply,
@@ -13,9 +14,13 @@ type XPendingRawReply = TuplesReply<[
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, group: RedisArgument) {
-    return ['XPENDING', key, group];
+  parseCommand(parser: CommandParser, key: RedisArgument, group: RedisArgument) {
+    parser.setCachable();
+    parser.push('XPENDING');
+    parser.pushKey(key);
+    parser.push(group);
   },
+  transformArguments(key: RedisArgument, group: RedisArgument) { return [] },
   transformReply(reply: UnwrapReply<XPendingRawReply>) {
     const consumers = reply[3] as unknown as UnwrapReply<typeof reply[3]>;
     return {
diff --git a/packages/client/lib/commands/XPENDING_RANGE.spec.ts b/packages/client/lib/commands/XPENDING_RANGE.spec.ts
index a66484fd2e6..33cd836f2a9 100644
--- a/packages/client/lib/commands/XPENDING_RANGE.spec.ts
+++ b/packages/client/lib/commands/XPENDING_RANGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XPENDING_RANGE from './XPENDING_RANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('XPENDING RANGE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1),
+        parseArgs(XPENDING_RANGE, 'key', 'group', '-', '+', 1),
         ['XPENDING', 'key', 'group', '-', '+', '1']
       );
     });
 
     it('with IDLE', () => {
       assert.deepEqual(
-        XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
+        parseArgs(XPENDING_RANGE, 'key', 'group', '-', '+', 1, {
           IDLE: 1,
         }),
         ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1']
@@ -22,7 +23,7 @@ describe('XPENDING RANGE', () => {
 
     it('with consumer', () => {
       assert.deepEqual(
-        XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
+        parseArgs(XPENDING_RANGE, 'key', 'group', '-', '+', 1, {
           consumer: 'consumer'
         }),
         ['XPENDING', 'key', 'group', '-', '+', '1', 'consumer']
@@ -31,7 +32,7 @@ describe('XPENDING RANGE', () => {
 
     it('with IDLE, consumer', () => {
       assert.deepEqual(
-        XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
+        parseArgs(XPENDING_RANGE, 'key', 'group', '-', '+', 1, {
           IDLE: 1,
           consumer: 'consumer'
         }),
diff --git a/packages/client/lib/commands/XPENDING_RANGE.ts b/packages/client/lib/commands/XPENDING_RANGE.ts
index 60a28e5172d..aba71fb8aae 100644
--- a/packages/client/lib/commands/XPENDING_RANGE.ts
+++ b/packages/client/lib/commands/XPENDING_RANGE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, NumberReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XPendingRangeOptions {
   IDLE?: number;
@@ -15,32 +16,44 @@ type XPendingRangeRawReply = ArrayReply<TuplesReply<[
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     group: RedisArgument,
     start: RedisArgument,
     end: RedisArgument,
     count: number,
     options?: XPendingRangeOptions
-  ) {
-    const args = ['XPENDING', key, group];
+  ) { 
+    parser.setCachable();
+    parser.push('XPENDING');
+    parser.pushKey(key);
+    parser.push(group);
 
     if (options?.IDLE !== undefined) {
-      args.push('IDLE', options.IDLE.toString());
+      parser.pushVariadic(['IDLE', options.IDLE.toString()]);
     }
 
-    args.push(
-      start,
-      end,
-      count.toString()
+    parser.pushVariadic(
+      [
+        start,
+        end,
+        count.toString()
+      ]
     );
 
     if (options?.consumer) {
-      args.push(options.consumer);
+      parser.push(options.consumer);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    group: RedisArgument,
+    start: RedisArgument,
+    end: RedisArgument,
+    count: number,
+    options?: XPendingRangeOptions
+  ) { return [] },
   transformReply(reply: UnwrapReply<XPendingRangeRawReply>) {
     return reply.map(pending => {
       const unwrapped = pending as unknown as UnwrapReply<typeof pending>;
diff --git a/packages/client/lib/commands/XRANGE.spec.ts b/packages/client/lib/commands/XRANGE.spec.ts
index ebfe271db86..b111a97aff1 100644
--- a/packages/client/lib/commands/XRANGE.spec.ts
+++ b/packages/client/lib/commands/XRANGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XRANGE from './XRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('XRANGE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XRANGE.transformArguments('key', '-', '+'),
+        parseArgs(XRANGE, 'key', '-', '+'),
         ['XRANGE', 'key', '-', '+']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        XRANGE.transformArguments('key', '-', '+', {
+        parseArgs(XRANGE, 'key', '-', '+', {
           COUNT: 1
         }),
         ['XRANGE', 'key', '-', '+', 'COUNT', '1']
diff --git a/packages/client/lib/commands/XRANGE.ts b/packages/client/lib/commands/XRANGE.ts
index 908e3d717fb..45d8e3286c9 100644
--- a/packages/client/lib/commands/XRANGE.ts
+++ b/packages/client/lib/commands/XRANGE.ts
@@ -1,18 +1,17 @@
 import { RedisArgument, ArrayReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { StreamMessageReply, transformStreamMessageReply } from './generic-transformers';
 
 export interface XRangeOptions {
   COUNT?: number;
 }
 
-export function transformXRangeArguments(
-  command: RedisArgument,
-  key: RedisArgument,
+export function xRangeArguments(
   start: RedisArgument,
   end: RedisArgument,
   options?: XRangeOptions
 ) {
-  const args = [command, key, start, end];
+  const args = [start, end];
 
   if (options?.COUNT) {
     args.push('COUNT', options.COUNT.toString());
@@ -21,9 +20,25 @@ export function transformXRangeArguments(
   return args;
 }
 
+export function transformXRangeArguments(
+  command: RedisArgument,
+  key: RedisArgument,
+  start: RedisArgument,
+  end: RedisArgument,
+  options?: XRangeOptions
+) {
+  return [command, key].concat(...xRangeArguments(start, end, options));
+}
+
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser, key: RedisArgument, ...args: Parameters<typeof xRangeArguments>) {
+    parser.setCachable();
+    parser.push('XRANGE');
+    parser.pushKey(key);
+    parser.pushVariadic(xRangeArguments(args[0], args[1], args[2]));
+  },
   transformArguments: transformXRangeArguments.bind(undefined, 'XRANGE'),
   transformReply(reply: UnwrapReply<ArrayReply<StreamMessageReply>>) {
     return reply.map(transformStreamMessageReply);
diff --git a/packages/client/lib/commands/XREAD.spec.ts b/packages/client/lib/commands/XREAD.spec.ts
index 69cd6cd6ffe..efb6ff53ce3 100644
--- a/packages/client/lib/commands/XREAD.spec.ts
+++ b/packages/client/lib/commands/XREAD.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
-import testUtils, { GLOBAL } from '../test-utils';
+import testUtils, { GLOBAL, parseFirstKey } from '../test-utils';
 import XREAD from './XREAD';
+import { parseArgs } from './generic-transformers';
 
 describe('XREAD', () => {
   describe('FIRST_KEY_INDEX', () => {
     it('single stream', () => {
       assert.equal(
-        XREAD.FIRST_KEY_INDEX({
+        parseFirstKey(XREAD, {
           key: 'key',
           id: ''
         }),
@@ -16,7 +17,7 @@ describe('XREAD', () => {
 
     it('multiple streams', () => {
       assert.equal(
-        XREAD.FIRST_KEY_INDEX([{
+        parseFirstKey(XREAD, [{
           key: '1',
           id: ''
         }, {
@@ -31,7 +32,7 @@ describe('XREAD', () => {
   describe('transformArguments', () => {
     it('single stream', () => {
       assert.deepEqual(
-        XREAD.transformArguments({
+        parseArgs(XREAD, {
           key: 'key',
           id: '0-0'
         }),
@@ -41,7 +42,7 @@ describe('XREAD', () => {
 
     it('multiple streams', () => {
       assert.deepEqual(
-        XREAD.transformArguments([{
+        parseArgs(XREAD, [{
           key: '1',
           id: '0-0'
         }, {
@@ -54,7 +55,7 @@ describe('XREAD', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        XREAD.transformArguments({
+        parseArgs(XREAD, {
           key: 'key',
           id: '0-0'
         }, {
@@ -66,7 +67,7 @@ describe('XREAD', () => {
 
     it('with BLOCK', () => {
       assert.deepEqual(
-        XREAD.transformArguments({
+        parseArgs(XREAD, {
           key: 'key',
           id: '0-0'
         }, {
@@ -78,7 +79,7 @@ describe('XREAD', () => {
 
     it('with COUNT, BLOCK', () => {
       assert.deepEqual(
-        XREAD.transformArguments({
+        parseArgs(XREAD, {
           key: 'key',
           id: '0-0'
         }, {
diff --git a/packages/client/lib/commands/XREAD.ts b/packages/client/lib/commands/XREAD.ts
index 2c1aa3d8277..5f5f897c3d8 100644
--- a/packages/client/lib/commands/XREAD.ts
+++ b/packages/client/lib/commands/XREAD.ts
@@ -1,4 +1,5 @@
 import { Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XReadStream {
   key: RedisArgument;
@@ -7,19 +8,19 @@ export interface XReadStream {
 
 export type XReadStreams = Array<XReadStream> | XReadStream;
 
-export function pushXReadStreams(args: Array<RedisArgument>, streams: XReadStreams) {
-  args.push('STREAMS');
+export function pushXReadStreams(parser: CommandParser, streams: XReadStreams) {
+  parser.push('STREAMS');
 
   if (Array.isArray(streams)) {
-    const keysStart = args.length,
-      idsStart = keysStart + streams.length;
     for (let i = 0; i < streams.length; i++) {
-      const stream = streams[i];
-      args[keysStart + i] = stream.key;
-      args[idsStart + i] = stream.id;
+      parser.pushKey(streams[i].key);
+    }
+    for (let i = 0; i < streams.length; i++) {
+      parser.push(streams[i].id);
     }
   } else {
-    args.push(streams.key, streams.id);
+    parser.pushKey(streams.key);
+    parser.push(streams.id);
   }
 }
 
@@ -33,21 +34,20 @@ export default {
     return Array.isArray(streams) ? streams[0].key : streams.key;
   },
   IS_READ_ONLY: true,
-  transformArguments(streams: XReadStreams, options?: XReadOptions) {
-    const args: Array<RedisArgument> = ['XREAD'];
+  parseCommand(parser: CommandParser, streams: XReadStreams, options?: XReadOptions) {
+    parser.push('XREAD');
 
     if (options?.COUNT) {
-      args.push('COUNT', options.COUNT.toString());
+      parser.pushVariadic(['COUNT', options.COUNT.toString()]);
     }
 
     if (options?.BLOCK !== undefined) {
-      args.push('BLOCK', options.BLOCK.toString());
+      parser.pushVariadic(['BLOCK', options.BLOCK.toString()]);
     }
 
-    pushXReadStreams(args, streams);
-
-    return args;
+    pushXReadStreams(parser, streams);
   },
+  transformArguments(streams: XReadStreams, options?: XReadOptions) { return [] },
   // export { transformStreamsMessagesReply as transformReply } from './generic-transformers';
   // TODO
   transformReply: undefined as unknown as () => unknown
diff --git a/packages/client/lib/commands/XREADGROUP.spec.ts b/packages/client/lib/commands/XREADGROUP.spec.ts
index 5ff16edcaa3..57553685f9c 100644
--- a/packages/client/lib/commands/XREADGROUP.spec.ts
+++ b/packages/client/lib/commands/XREADGROUP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
-import testUtils, { GLOBAL } from '../test-utils';
+import testUtils, { GLOBAL, parseFirstKey } from '../test-utils';
 import XREADGROUP from './XREADGROUP';
+import { parseArgs } from './generic-transformers';
 
 describe('XREADGROUP', () => {
   describe('FIRST_KEY_INDEX', () => {
     it('single stream', () => {
       assert.equal(
-        XREADGROUP.FIRST_KEY_INDEX('', '', { key: 'key', id: '' }),
+        parseFirstKey(XREADGROUP, '', '', { key: 'key', id: '' }),
         'key'
       );
     });
 
     it('multiple streams', () => {
       assert.equal(
-        XREADGROUP.FIRST_KEY_INDEX('', '', [{ key: '1', id: '' }, { key: '2', id: '' }]),
+        parseFirstKey(XREADGROUP, '', '', [{ key: '1', id: '' }, { key: '2', id: '' }]),
         '1'
       );
     });
@@ -22,7 +23,7 @@ describe('XREADGROUP', () => {
   describe('transformArguments', () => {
     it('single stream', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', {
+        parseArgs(XREADGROUP, 'group', 'consumer', {
           key: 'key',
           id: '0-0'
         }),
@@ -32,7 +33,7 @@ describe('XREADGROUP', () => {
 
     it('multiple streams', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', [{
+        parseArgs(XREADGROUP, 'group', 'consumer', [{
           key: '1',
           id: '0-0'
         }, {
@@ -45,7 +46,7 @@ describe('XREADGROUP', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', {
+        parseArgs(XREADGROUP, 'group', 'consumer', {
           key: 'key',
           id: '0-0'
         }, {
@@ -57,7 +58,7 @@ describe('XREADGROUP', () => {
 
     it('with BLOCK', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', {
+        parseArgs(XREADGROUP, 'group', 'consumer', {
           key: 'key',
           id: '0-0'
         }, {
@@ -69,7 +70,7 @@ describe('XREADGROUP', () => {
 
     it('with NOACK', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', {
+        parseArgs(XREADGROUP, 'group', 'consumer', {
           key: 'key',
           id: '0-0'
         }, {
@@ -81,7 +82,7 @@ describe('XREADGROUP', () => {
 
     it('with COUNT, BLOCK, NOACK', () => {
       assert.deepEqual(
-        XREADGROUP.transformArguments('group', 'consumer', {
+        parseArgs(XREADGROUP, 'group', 'consumer', {
           key: 'key',
           id: '0-0'
         }, {
diff --git a/packages/client/lib/commands/XREADGROUP.ts b/packages/client/lib/commands/XREADGROUP.ts
index 0396f3a93e9..a485c085f3c 100644
--- a/packages/client/lib/commands/XREADGROUP.ts
+++ b/packages/client/lib/commands/XREADGROUP.ts
@@ -1,4 +1,5 @@
 import { Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import XREAD, { XReadStreams, pushXReadStreams } from './XREAD';
 
 export interface XReadGroupOptions {
@@ -16,30 +17,35 @@ export default {
     return XREAD.FIRST_KEY_INDEX(streams);
   },
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     group: RedisArgument,
     consumer: RedisArgument,
     streams: XReadStreams,
     options?: XReadGroupOptions
   ) {
-    const args = ['XREADGROUP', 'GROUP', group, consumer];
+    parser.pushVariadic(['XREADGROUP', 'GROUP', group, consumer]);
 
     if (options?.COUNT !== undefined) {
-      args.push('COUNT', options.COUNT.toString());
+      parser.pushVariadic(['COUNT', options.COUNT.toString()]);
     }
 
     if (options?.BLOCK !== undefined) {
-      args.push('BLOCK', options.BLOCK.toString());
+      parser.pushVariadic(['BLOCK', options.BLOCK.toString()]);
     }
 
     if (options?.NOACK) {
-      args.push('NOACK');
+      parser.push('NOACK');
     }
 
-    pushXReadStreams(args, streams);
-
-    return args;
+    pushXReadStreams(parser, streams);
   },
+  transformArguments(
+    group: RedisArgument,
+    consumer: RedisArgument,
+    streams: XReadStreams,
+    options?: XReadGroupOptions
+  ) { return [] },
   // export { transformStreamsMessagesReply as transformReply } from './generic-transformers';
   // TODO
   transformReply: undefined as unknown as () => unknown
diff --git a/packages/client/lib/commands/XREVRANGE.spec.ts b/packages/client/lib/commands/XREVRANGE.spec.ts
index c9f3043af38..9872dc5e9e0 100644
--- a/packages/client/lib/commands/XREVRANGE.spec.ts
+++ b/packages/client/lib/commands/XREVRANGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XREVRANGE from './XREVRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('XREVRANGE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XREVRANGE.transformArguments('key', '-', '+'),
+        parseArgs(XREVRANGE, 'key', '-', '+'),
         ['XREVRANGE', 'key', '-', '+']
       );
     });
 
     it('with COUNT', () => {
       assert.deepEqual(
-        XREVRANGE.transformArguments('key', '-', '+', {
+        parseArgs(XREVRANGE, 'key', '-', '+', {
           COUNT: 1
         }),
         ['XREVRANGE', 'key', '-', '+', 'COUNT', '1']
diff --git a/packages/client/lib/commands/XREVRANGE.ts b/packages/client/lib/commands/XREVRANGE.ts
index 86e4d8abc9e..a5120ceb89c 100644
--- a/packages/client/lib/commands/XREVRANGE.ts
+++ b/packages/client/lib/commands/XREVRANGE.ts
@@ -1,5 +1,6 @@
-import { Command } from '../RESP/types';
-import XRANGE, { transformXRangeArguments } from './XRANGE';
+import { Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
+import XRANGE, { transformXRangeArguments, xRangeArguments } from './XRANGE';
 
 export interface XRevRangeOptions {
   COUNT?: number;
@@ -8,6 +9,12 @@ export interface XRevRangeOptions {
 export default {
   FIRST_KEY_INDEX: XRANGE.FIRST_KEY_INDEX,
   IS_READ_ONLY: XRANGE.IS_READ_ONLY,
+  parseCommand(parser: CommandParser, key: RedisArgument, ...args: Parameters<typeof xRangeArguments>) {
+    parser.setCachable();
+    parser.push('XREVRANGE');
+    parser.pushKey(key);
+    parser.pushVariadic(xRangeArguments(args[0], args[1], args[2]));
+  },
   transformArguments: transformXRangeArguments.bind(undefined, 'XREVRANGE'),
   transformReply: XRANGE.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/XSETID.spec.ts b/packages/client/lib/commands/XSETID.spec.ts
index 5ebbc943816..b3609695345 100644
--- a/packages/client/lib/commands/XSETID.spec.ts
+++ b/packages/client/lib/commands/XSETID.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XSETID from './XSETID';
+import { parseArgs } from './generic-transformers';
 
 describe('XSETID', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XSETID.transformArguments('key', '0-0'),
+        parseArgs(XSETID, 'key', '0-0'),
         ['XSETID', 'key', '0-0']
       );
     });
 
     it('with ENTRIESADDED', () => {
       assert.deepEqual(
-        XSETID.transformArguments('key', '0-0', {
+        parseArgs(XSETID, 'key', '0-0', {
           ENTRIESADDED: 1
         }),
         ['XSETID', 'key', '0-0', 'ENTRIESADDED', '1']
@@ -22,7 +23,7 @@ describe('XSETID', () => {
 
     it('with MAXDELETEDID', () => {
       assert.deepEqual(
-        XSETID.transformArguments('key', '0-0', {
+        parseArgs(XSETID, 'key', '0-0', {
           MAXDELETEDID: '1-1'
         }),
         ['XSETID', 'key', '0-0', 'MAXDELETEDID', '1-1']
diff --git a/packages/client/lib/commands/XSETID.ts b/packages/client/lib/commands/XSETID.ts
index a2ac8af0011..ad6806f2f2f 100644
--- a/packages/client/lib/commands/XSETID.ts
+++ b/packages/client/lib/commands/XSETID.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 export interface XSetIdOptions {
   /** added in 7.0 */
   ENTRIESADDED?: number;
@@ -9,23 +10,25 @@ export interface XSetIdOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     lastId: RedisArgument,
     options?: XSetIdOptions
   ) {
-    const args = ['XSETID', key, lastId];
+    parser.push('XSETID');
+    parser.pushKey(key);
+    parser.push(lastId);
 
     if (options?.ENTRIESADDED) {
-      args.push('ENTRIESADDED', options.ENTRIESADDED.toString());
+      parser.pushVariadic(['ENTRIESADDED', options.ENTRIESADDED.toString()]);
     }
 
     if (options?.MAXDELETEDID) {
-      args.push('MAXDELETEDID', options.MAXDELETEDID);
+      parser.pushVariadic(['MAXDELETEDID', options.MAXDELETEDID]);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, lastId: RedisArgument, options?: XSetIdOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/XTRIM.spec.ts b/packages/client/lib/commands/XTRIM.spec.ts
index a5a2fdf23c5..2c31f0fef92 100644
--- a/packages/client/lib/commands/XTRIM.spec.ts
+++ b/packages/client/lib/commands/XTRIM.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import XTRIM from './XTRIM';
+import { parseArgs } from './generic-transformers';
 
 describe('XTRIM', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        XTRIM.transformArguments('key', 'MAXLEN', 1),
+        parseArgs(XTRIM, 'key', 'MAXLEN', 1),
         ['XTRIM', 'key', 'MAXLEN', '1']
       );
     });
 
     it('with strategyModifier', () => {
       assert.deepEqual(
-        XTRIM.transformArguments('key', 'MAXLEN', 1, {
+        parseArgs(XTRIM, 'key', 'MAXLEN', 1, {
           strategyModifier: '='
         }),
         ['XTRIM', 'key', 'MAXLEN', '=', '1']
@@ -22,7 +23,7 @@ describe('XTRIM', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        XTRIM.transformArguments('key', 'MAXLEN', 1, {
+        parseArgs(XTRIM, 'key', 'MAXLEN', 1, {
           LIMIT: 1
         }),
         ['XTRIM', 'key', 'MAXLEN', '1', 'LIMIT', '1']
@@ -31,7 +32,7 @@ describe('XTRIM', () => {
 
     it('with strategyModifier, LIMIT', () => {
       assert.deepEqual(
-        XTRIM.transformArguments('key', 'MAXLEN', 1, {
+        parseArgs(XTRIM, 'key', 'MAXLEN', 1, {
           strategyModifier: '=',
           LIMIT: 1
         }),
diff --git a/packages/client/lib/commands/XTRIM.ts b/packages/client/lib/commands/XTRIM.ts
index 0512323a32a..eb64e2efe01 100644
--- a/packages/client/lib/commands/XTRIM.ts
+++ b/packages/client/lib/commands/XTRIM.ts
@@ -1,4 +1,5 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export interface XTrimOptions {
   strategyModifier?: '=' | '~';
@@ -9,25 +10,27 @@ export interface XTrimOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     strategy: 'MAXLEN' | 'MINID',
     threshold: number,
     options?: XTrimOptions
   ) {
-    const args = ['XTRIM', key, strategy];
+    parser.push('XTRIM')
+    parser.pushKey(key);
+    parser.push(strategy);
 
     if (options?.strategyModifier) {
-      args.push(options.strategyModifier);
+      parser.push(options.strategyModifier);
     }
 
-    args.push(threshold.toString());
+    parser.push(threshold.toString());
 
     if (options?.LIMIT) {
-      args.push('LIMIT', options.LIMIT.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.toString()]);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, strategy: 'MAXLEN' | 'MINID', threshold: number, options?: XTrimOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZADD.spec.ts b/packages/client/lib/commands/ZADD.spec.ts
index 5f64cb13b92..0e770693e3a 100644
--- a/packages/client/lib/commands/ZADD.spec.ts
+++ b/packages/client/lib/commands/ZADD.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZADD from './ZADD';
+import { parseArgs } from './generic-transformers';
 
 describe('ZADD', () => {
   describe('transformArguments', () => {
     it('single member', () => {
       assert.deepEqual(
-        ZADD.transformArguments('key', {
+        parseArgs(ZADD, 'key', {
           value: '1',
           score: 1
         }),
@@ -16,7 +17,7 @@ describe('ZADD', () => {
 
     it('multiple members', () => {
       assert.deepEqual(
-        ZADD.transformArguments('key', [{
+        parseArgs(ZADD, 'key', [{
           value: '1',
           score: 1
         }, {
@@ -30,7 +31,7 @@ describe('ZADD', () => {
     describe('with condition', () => {
       it('condition property', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -42,7 +43,7 @@ describe('ZADD', () => {
 
       it('with NX (backwards compatibility)', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -54,7 +55,7 @@ describe('ZADD', () => {
 
       it('with XX (backwards compatibility)', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -68,7 +69,7 @@ describe('ZADD', () => {
     describe('with comparison', () => {
       it('with LT', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -80,7 +81,7 @@ describe('ZADD', () => {
 
       it('with LT (backwards compatibility)', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -92,7 +93,7 @@ describe('ZADD', () => {
 
       it('with GT (backwards compatibility)', () => {
         assert.deepEqual(
-          ZADD.transformArguments('key', {
+          parseArgs(ZADD, 'key', {
             value: '1',
             score: 1
           }, {
@@ -105,7 +106,7 @@ describe('ZADD', () => {
 
     it('with CH', () => {
       assert.deepEqual(
-        ZADD.transformArguments('key', {
+        parseArgs(ZADD, 'key', {
           value: '1',
           score: 1
         }, {
@@ -117,7 +118,7 @@ describe('ZADD', () => {
 
     it('with condition, comparison, CH', () => {
       assert.deepEqual(
-        ZADD.transformArguments('key', {
+        parseArgs(ZADD, 'key', {
           value: '1',
           score: 1
         }, {
diff --git a/packages/client/lib/commands/ZADD.ts b/packages/client/lib/commands/ZADD.ts
index 0c5602bf988..aa713d54308 100644
--- a/packages/client/lib/commands/ZADD.ts
+++ b/packages/client/lib/commands/ZADD.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { SortedSetMember, transformDoubleArgument, transformDoubleReply } from './generic-transformers';
 
 export interface ZAddOptions {
@@ -25,58 +26,61 @@ export interface ZAddOptions {
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     members: SortedSetMember | Array<SortedSetMember>,
     options?: ZAddOptions
   ) {
-    const args = ['ZADD', key];
+    parser.push('ZADD');
+    parser.pushKey(key);
 
     if (options?.condition) {
-      args.push(options.condition);
+      parser.push(options.condition);
     } else if (options?.NX) {
-      args.push('NX');
+      parser.push('NX');
     } else if (options?.XX) {
-      args.push('XX');
+      parser.push('XX');
     } 
 
     if (options?.comparison) {
-      args.push(options.comparison);
+      parser.push(options.comparison);
     } else if (options?.LT) {
-      args.push('LT');
+      parser.push('LT');
     } else if (options?.GT) {
-      args.push('GT');
+      parser.push('GT');
     }
 
     if (options?.CH) {
-      args.push('CH');
+      parser.push('CH');
     }
 
-    pushMembers(args, members);
-
-    return args;
+    pushMembers(parser, members);
   },
+  transformArguments(key: RedisArgument, members: SortedSetMember | Array<SortedSetMember>, options?: ZAddOptions) { return [] },
   transformReply: transformDoubleReply
 } as const satisfies Command;
 
 export function pushMembers(
-  args: Array<RedisArgument>,
+  parser: CommandParser,
   members: SortedSetMember | Array<SortedSetMember>) {
   if (Array.isArray(members)) {
     for (const member of members) {
-      pushMember(args, member);
+      pushMember(parser, member);
     }
   } else {
-    pushMember(args, members);
+    pushMember(parser, members);
   }
 }
 
 function pushMember(
-  args: Array<RedisArgument>,
+  parser: CommandParser,
   member: SortedSetMember
 ) {
-  args.push(
-    transformDoubleArgument(member.score),
-    member.value
+  parser.pushVariadic(
+    [
+      transformDoubleArgument(member.score),
+      member.value
+    ]
   );
 }
diff --git a/packages/client/lib/commands/ZADD_INCR.spec.ts b/packages/client/lib/commands/ZADD_INCR.spec.ts
index c6ffcb796f3..df9ac87f449 100644
--- a/packages/client/lib/commands/ZADD_INCR.spec.ts
+++ b/packages/client/lib/commands/ZADD_INCR.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZADD_INCR from './ZADD_INCR';
+import { parseArgs } from './generic-transformers';
 
 describe('ZADD INCR', () => {
   describe('transformArguments', () => {
     it('single member', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', {
+        parseArgs(ZADD_INCR, 'key', {
           value: '1',
           score: 1
         }),
@@ -16,7 +17,7 @@ describe('ZADD INCR', () => {
 
     it('multiple members', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', [{
+        parseArgs(ZADD_INCR, 'key', [{
           value: '1',
           score: 1
         }, {
@@ -29,7 +30,7 @@ describe('ZADD INCR', () => {
 
     it('with condition', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', {
+        parseArgs(ZADD_INCR, 'key', {
           value: '1',
           score: 1
         }, {
@@ -41,7 +42,7 @@ describe('ZADD INCR', () => {
 
     it('with comparison', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', {
+        parseArgs(ZADD_INCR, 'key', {
           value: '1',
           score: 1
         }, {
@@ -53,7 +54,7 @@ describe('ZADD INCR', () => {
 
     it('with CH', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', {
+        parseArgs(ZADD_INCR, 'key', {
           value: '1',
           score: 1
         }, {
@@ -65,7 +66,7 @@ describe('ZADD INCR', () => {
 
     it('with condition, comparison, CH', () => {
       assert.deepEqual(
-        ZADD_INCR.transformArguments('key', {
+        parseArgs(ZADD_INCR, 'key', {
           value: '1',
           score: 1
         }, {
diff --git a/packages/client/lib/commands/ZADD_INCR.ts b/packages/client/lib/commands/ZADD_INCR.ts
index 8fb10721674..8883e442966 100644
--- a/packages/client/lib/commands/ZADD_INCR.ts
+++ b/packages/client/lib/commands/ZADD_INCR.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { pushMembers } from './ZADD';
 import { SortedSetMember, transformNullableDoubleReply } from './generic-transformers';
 
@@ -10,30 +11,31 @@ export interface ZAddOptions {
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     members: SortedSetMember | Array<SortedSetMember>,
     options?: ZAddOptions
   ) {
-    const args = ['ZADD', key];
+    parser.push('ZADD');
+    parser.pushKey(key);
 
     if (options?.condition) {
-      args.push(options.condition);
+      parser.push(options.condition);
     }
 
     if (options?.comparison) {
-      args.push(options.comparison);
+      parser.push(options.comparison);
     }
 
     if (options?.CH) {
-      args.push('CH');
+      parser.push('CH');
     }
 
-    args.push('INCR');
+    parser.push('INCR');
 
-    pushMembers(args, members);
-
-    return args;
+    pushMembers(parser, members);
   },
+  transformArguments(key: RedisArgument, members: SortedSetMember | Array<SortedSetMember>, options?: ZAddOptions) { return [] },
   transformReply: transformNullableDoubleReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZCARD.spec.ts b/packages/client/lib/commands/ZCARD.spec.ts
index ff4bb881fb7..44adec0833a 100644
--- a/packages/client/lib/commands/ZCARD.spec.ts
+++ b/packages/client/lib/commands/ZCARD.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZCARD from './ZCARD';
+import { parseArgs } from './generic-transformers';
 
 describe('ZCARD', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZCARD.transformArguments('key'),
+      parseArgs(ZCARD, 'key'),
       ['ZCARD', 'key']
     );
   });
diff --git a/packages/client/lib/commands/ZCARD.ts b/packages/client/lib/commands/ZCARD.ts
index c11cb69db3c..01ab04c443d 100644
--- a/packages/client/lib/commands/ZCARD.ts
+++ b/packages/client/lib/commands/ZCARD.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['ZCARD', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.setCachable();
+    parser.push('ZCARD');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZCOUNT.spec.ts b/packages/client/lib/commands/ZCOUNT.spec.ts
index 357f24bd796..5d279d7a4ca 100644
--- a/packages/client/lib/commands/ZCOUNT.spec.ts
+++ b/packages/client/lib/commands/ZCOUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZCOUNT from './ZCOUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('ZCOUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZCOUNT.transformArguments('key', 0, 1),
+      parseArgs(ZCOUNT, 'key', 0, 1),
       ['ZCOUNT', 'key', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZCOUNT.ts b/packages/client/lib/commands/ZCOUNT.ts
index 187a316b15a..57f6ba103f1 100644
--- a/packages/client/lib/commands/ZCOUNT.ts
+++ b/packages/client/lib/commands/ZCOUNT.ts
@@ -1,20 +1,30 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser, 
     key: RedisArgument,
     min: number | RedisArgument,
     max: number | RedisArgument
   ) {
-    return [
-      'ZCOUNT',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.setCachable();
+    parser.push('ZCOUNT');
+    parser.push(key);
+    parser.pushVariadic(
+      [
+        transformStringDoubleArgument(min), 
+        transformStringDoubleArgument(max)
+      ]
+    );
   },
+  transformArguments(
+    key: RedisArgument,
+    min: number | RedisArgument,
+    max: number | RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZDIFF.spec.ts b/packages/client/lib/commands/ZDIFF.spec.ts
index a285190398c..4914df3e978 100644
--- a/packages/client/lib/commands/ZDIFF.spec.ts
+++ b/packages/client/lib/commands/ZDIFF.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZDIFF from './ZDIFF';
+import { parseArgs } from './generic-transformers';
 
 describe('ZDIFF', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('ZDIFF', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ZDIFF.transformArguments('key'),
+        parseArgs(ZDIFF, 'key'),
         ['ZDIFF', '1', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ZDIFF.transformArguments(['1', '2']),
+        parseArgs(ZDIFF, ['1', '2']),
         ['ZDIFF', '2', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/ZDIFF.ts b/packages/client/lib/commands/ZDIFF.ts
index f16c8717cdb..b6d82cdacf8 100644
--- a/packages/client/lib/commands/ZDIFF.ts
+++ b/packages/client/lib/commands/ZDIFF.ts
@@ -1,11 +1,14 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(keys: RedisVariadicArgument) {
-    return pushVariadicArgument(['ZDIFF'], keys);
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    parser.push('ZDIFF');
+    parser.pushKeysLength(keys);
   },
+  transformArguments(keys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZDIFFSTORE.spec.ts b/packages/client/lib/commands/ZDIFFSTORE.spec.ts
index 1bd779302bf..7f380cfc532 100644
--- a/packages/client/lib/commands/ZDIFFSTORE.spec.ts
+++ b/packages/client/lib/commands/ZDIFFSTORE.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZDIFFSTORE from './ZDIFFSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZDIFFSTORE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('ZDIFFSTORE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ZDIFFSTORE.transformArguments('destination', 'key'),
+        parseArgs(ZDIFFSTORE, 'destination', 'key'),
         ['ZDIFFSTORE', 'destination', '1', 'key']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ZDIFFSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(ZDIFFSTORE, 'destination', ['1', '2']),
         ['ZDIFFSTORE', 'destination', '2', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/ZDIFFSTORE.ts b/packages/client/lib/commands/ZDIFFSTORE.ts
index e4614a1cb14..4dae5ec80a6 100644
--- a/packages/client/lib/commands/ZDIFFSTORE.ts
+++ b/packages/client/lib/commands/ZDIFFSTORE.ts
@@ -1,14 +1,15 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
-    destination: RedisArgument,
-    inputKeys: RedisVariadicArgument
-  ) {
-    return pushVariadicArgument(['ZDIFFSTORE', destination], inputKeys);
+  parseCommand(parser: CommandParser, destination: RedisArgument, inputKeys: RedisVariadicArgument) {
+    parser.push('ZDIFFSTORE');
+    parser.pushKey(destination);
+    parser.pushKeysLength(inputKeys);
   },
+  transformArguments(destination: RedisArgument, inputKeys: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZDIFF_WITHSCORES.spec.ts b/packages/client/lib/commands/ZDIFF_WITHSCORES.spec.ts
index 4fcd1f978a3..bea639f223e 100644
--- a/packages/client/lib/commands/ZDIFF_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZDIFF_WITHSCORES.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZDIFF_WITHSCORES from './ZDIFF_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZDIFF WITHSCORES', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('ZDIFF WITHSCORES', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ZDIFF_WITHSCORES.transformArguments('key'),
+        parseArgs(ZDIFF_WITHSCORES, 'key'),
         ['ZDIFF', '1', 'key', 'WITHSCORES']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ZDIFF_WITHSCORES.transformArguments(['1', '2']),
+        parseArgs(ZDIFF_WITHSCORES, ['1', '2']),
         ['ZDIFF', '2', '1', '2', 'WITHSCORES']
       );
     });
diff --git a/packages/client/lib/commands/ZDIFF_WITHSCORES.ts b/packages/client/lib/commands/ZDIFF_WITHSCORES.ts
index f971e828574..e5745013776 100644
--- a/packages/client/lib/commands/ZDIFF_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZDIFF_WITHSCORES.ts
@@ -1,14 +1,15 @@
 import { Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZDIFF from './ZDIFF';
-import { transformSortedSetReply } from './generic-transformers';
+import { RedisVariadicArgument, transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: ZDIFF.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZDIFF.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZDIFF.transformArguments>) {
-    const redisArgs = ZDIFF.transformArguments(...args);
-    redisArgs.push('WITHSCORES');
-    return redisArgs;
+  parseCommand(parser: CommandParser, keys: RedisVariadicArgument) {
+    ZDIFF.parseCommand(parser, keys);
+    parser.push('WITHSCORES');
   },
+  transformArguments(...args: Parameters<typeof ZDIFF.transformArguments>) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZINCRBY.spec.ts b/packages/client/lib/commands/ZINCRBY.spec.ts
index fea3c7a2f71..8f6c5141252 100644
--- a/packages/client/lib/commands/ZINCRBY.spec.ts
+++ b/packages/client/lib/commands/ZINCRBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZINCRBY from './ZINCRBY';
+import { parseArgs } from './generic-transformers';
 
 describe('ZINCRBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZINCRBY.transformArguments('key', 1, 'member'),
+      parseArgs(ZINCRBY, 'key', 1, 'member'),
       ['ZINCRBY', 'key', '1', 'member']
     );
   });
diff --git a/packages/client/lib/commands/ZINCRBY.ts b/packages/client/lib/commands/ZINCRBY.ts
index d9e43845016..d7e676f31d7 100644
--- a/packages/client/lib/commands/ZINCRBY.ts
+++ b/packages/client/lib/commands/ZINCRBY.ts
@@ -1,19 +1,19 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformDoubleArgument, transformDoubleReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     increment: number,
     member: RedisArgument
   ) {
-    return [
-      'ZINCRBY',
-      key,
-      transformDoubleArgument(increment),
-      member
-    ];
+    parser.push('ZINCRBY');
+    parser.pushKey(key);
+    parser.pushVariadic([transformDoubleArgument(increment), member]);
   },
+  transformArguments(key: RedisArgument, increment: number, member: RedisArgument) { return [] },
   transformReply: transformDoubleReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZINTER.spec.ts b/packages/client/lib/commands/ZINTER.spec.ts
index 0d678ce1151..73df0935de9 100644
--- a/packages/client/lib/commands/ZINTER.spec.ts
+++ b/packages/client/lib/commands/ZINTER.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZINTER from './ZINTER';
+import { parseArgs } from './generic-transformers';
 
 describe('ZINTER', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,21 +9,21 @@ describe('ZINTER', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZINTER.transformArguments('key'),
+        parseArgs(ZINTER, 'key'),
         ['ZINTER', '1', 'key']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZINTER.transformArguments(['1', '2']),
+        parseArgs(ZINTER, ['1', '2']),
         ['ZINTER', '2', '1', '2']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZINTER.transformArguments({
+        parseArgs(ZINTER, {
           key: 'key',
           weight: 1
         }),
@@ -32,7 +33,7 @@ describe('ZINTER', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZINTER.transformArguments([{
+        parseArgs(ZINTER, [{
           key: 'a',
           weight: 1
         }, {
@@ -45,7 +46,7 @@ describe('ZINTER', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZINTER.transformArguments('key', {
+        parseArgs(ZINTER, 'key', {
           AGGREGATE: 'SUM'
         }),
         ['ZINTER', '1', 'key', 'AGGREGATE', 'SUM']
diff --git a/packages/client/lib/commands/ZINTER.ts b/packages/client/lib/commands/ZINTER.ts
index 392c3a96c65..3eafd55b5e3 100644
--- a/packages/client/lib/commands/ZINTER.ts
+++ b/packages/client/lib/commands/ZINTER.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { ZKeys, pushZKeysArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { ZKeys, parseZKeysArguments } from './generic-transformers';
 
 export type ZInterKeyAndWeight = {
   key: RedisArgument;
@@ -8,32 +9,31 @@ export type ZInterKeyAndWeight = {
 
 export type ZInterKeys<T> = T | [T, ...Array<T>];
 
+export type ZInterKeysType = ZInterKeys<RedisArgument> | ZInterKeys<ZInterKeyAndWeight>;
+
 export interface ZInterOptions {
   AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
 }
 
-export function pushZInterArguments(
-  args: Array<RedisArgument>,
+export function parseZInterArguments(
+  parser: CommandParser,
   keys: ZKeys,
   options?: ZInterOptions
 ) {
-  args = pushZKeysArguments(args, keys);
+  parseZKeysArguments(parser, keys);
 
   if (options?.AGGREGATE) {
-    args.push('AGGREGATE', options.AGGREGATE);
+    parser.pushVariadic(['AGGREGATE', options.AGGREGATE]);
   }
-
-  return args;
 }
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
-    keys: ZInterKeys<RedisArgument> | ZInterKeys<ZInterKeyAndWeight>,
-    options?: ZInterOptions
-  ) {
-    return pushZInterArguments(['ZINTER'], keys, options);
+  parseCommand(parser: CommandParser, keys: ZInterKeysType, options?: ZInterOptions) {
+    parser.push('ZINTER');
+    parseZInterArguments(parser, keys, options);
   },
+  transformArguments(keys: ZInterKeysType, options?: ZInterOptions) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZINTERCARD.spec.ts b/packages/client/lib/commands/ZINTERCARD.spec.ts
index 312e2825ff4..5204872a2d0 100644
--- a/packages/client/lib/commands/ZINTERCARD.spec.ts
+++ b/packages/client/lib/commands/ZINTERCARD.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZINTERCARD from './ZINTERCARD';
+import { parseArgs } from './generic-transformers';
 
 describe('ZINTERCARD', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,7 +9,7 @@ describe('ZINTERCARD', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZINTERCARD.transformArguments(['1', '2']),
+        parseArgs(ZINTERCARD, ['1', '2']),
         ['ZINTERCARD', '2', '1', '2']
       );
     });
@@ -16,14 +17,14 @@ describe('ZINTERCARD', () => {
     describe('with LIMIT', () => {
       it('plain number (backwards compatibility)', () => {
         assert.deepEqual(
-          ZINTERCARD.transformArguments(['1', '2'], 1),
+          parseArgs(ZINTERCARD, ['1', '2'], 1),
           ['ZINTERCARD', '2', '1', '2', 'LIMIT', '1']
         );
       });
 
       it('{ LIMIT: number }', () => {
         assert.deepEqual(
-          ZINTERCARD.transformArguments(['1', '2'], {
+          parseArgs(ZINTERCARD, ['1', '2'], {
             LIMIT: 1
           }),
           ['ZINTERCARD', '2', '1', '2', 'LIMIT', '1']
diff --git a/packages/client/lib/commands/ZINTERCARD.ts b/packages/client/lib/commands/ZINTERCARD.ts
index 9953d88eecc..ab38698d809 100644
--- a/packages/client/lib/commands/ZINTERCARD.ts
+++ b/packages/client/lib/commands/ZINTERCARD.ts
@@ -1,5 +1,6 @@
 import { NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export interface ZInterCardOptions {
   LIMIT?: number;
@@ -8,20 +9,21 @@ export interface ZInterCardOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     keys: RedisVariadicArgument,
     options?: ZInterCardOptions['LIMIT'] | ZInterCardOptions
   ) {
-    const args = pushVariadicArgument(['ZINTERCARD'], keys);
+    parser.push('ZINTERCARD');
+    parser.pushKeysLength(keys);
 
     // backwards compatibility
     if (typeof options === 'number') {
-      args.push('LIMIT', options.toString());
+      parser.pushVariadic(['LIMIT', options.toString()]);
     } else if (options?.LIMIT) {
-      args.push('LIMIT', options.LIMIT.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.toString()]);
     }
-
-    return args;
   },
+  transformArguments(keys: RedisVariadicArgument, options?: ZInterCardOptions['LIMIT'] | ZInterCardOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZINTERSTORE.spec.ts b/packages/client/lib/commands/ZINTERSTORE.spec.ts
index 27914ca0327..c6b448ab908 100644
--- a/packages/client/lib/commands/ZINTERSTORE.spec.ts
+++ b/packages/client/lib/commands/ZINTERSTORE.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZINTERSTORE from './ZINTERSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZINTERSTORE', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZINTERSTORE.transformArguments('destination', 'source'),
+        parseArgs(ZINTERSTORE, 'destination', 'source'),
         ['ZINTERSTORE', 'destination', '1', 'source']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZINTERSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(ZINTERSTORE, 'destination', ['1', '2']),
         ['ZINTERSTORE', 'destination', '2', '1', '2']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZINTERSTORE.transformArguments('destination', {
+        parseArgs(ZINTERSTORE, 'destination', {
           key: 'source',
           weight: 1
         }),
@@ -30,7 +31,7 @@ describe('ZINTERSTORE', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZINTERSTORE.transformArguments('destination', [{
+        parseArgs(ZINTERSTORE, 'destination', [{
           key: 'a',
           weight: 1
         }, {
@@ -43,7 +44,7 @@ describe('ZINTERSTORE', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZINTERSTORE.transformArguments('destination', 'source', {
+        parseArgs(ZINTERSTORE, 'destination', 'source', {
           AGGREGATE: 'SUM'
         }),
         ['ZINTERSTORE', 'destination', '1', 'source', 'AGGREGATE', 'SUM']
diff --git a/packages/client/lib/commands/ZINTERSTORE.ts b/packages/client/lib/commands/ZINTERSTORE.ts
index a5334566d73..cce432da4e6 100644
--- a/packages/client/lib/commands/ZINTERSTORE.ts
+++ b/packages/client/lib/commands/ZINTERSTORE.ts
@@ -1,17 +1,22 @@
 
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { pushZInterArguments, ZInterOptions } from './ZINTER';
+import { CommandParser } from '../client/parser';
+import { parseZInterArguments, ZInterOptions } from './ZINTER';
 import { ZKeys } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     destination: RedisArgument,
     keys: ZKeys,
     options?: ZInterOptions
   ) {
-    return pushZInterArguments(['ZINTERSTORE', destination], keys, options);
+    parser.push('ZINTERSTORE');
+    parser.pushKey(destination);
+    parseZInterArguments(parser, keys, options);
   },
+  transformArguments(destination: RedisArgument, keys: ZKeys, options?: ZInterOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZINTER_WITHSCORES.spec.ts b/packages/client/lib/commands/ZINTER_WITHSCORES.spec.ts
index 05790510e49..234b250b143 100644
--- a/packages/client/lib/commands/ZINTER_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZINTER_WITHSCORES.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZINTER_WITHSCORES from './ZINTER_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZINTER WITHSCORES', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,21 +9,21 @@ describe('ZINTER WITHSCORES', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZINTER_WITHSCORES.transformArguments('key'),
+        parseArgs(ZINTER_WITHSCORES, 'key'),
         ['ZINTER', '1', 'key', 'WITHSCORES']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZINTER_WITHSCORES.transformArguments(['1', '2']),
+        parseArgs(ZINTER_WITHSCORES, ['1', '2']),
         ['ZINTER', '2', '1', '2', 'WITHSCORES']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZINTER_WITHSCORES.transformArguments({
+        parseArgs(ZINTER_WITHSCORES, {
           key: 'key',
           weight: 1
         }),
@@ -32,7 +33,7 @@ describe('ZINTER WITHSCORES', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZINTER_WITHSCORES.transformArguments([{
+        parseArgs(ZINTER_WITHSCORES, [{
           key: 'a',
           weight: 1
         }, {
@@ -45,7 +46,7 @@ describe('ZINTER WITHSCORES', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZINTER_WITHSCORES.transformArguments('key', {
+        parseArgs(ZINTER_WITHSCORES, 'key', {
           AGGREGATE: 'SUM'
         }),
         ['ZINTER', '1', 'key', 'AGGREGATE', 'SUM', 'WITHSCORES']
diff --git a/packages/client/lib/commands/ZINTER_WITHSCORES.ts b/packages/client/lib/commands/ZINTER_WITHSCORES.ts
index b287649fbc0..69028fdc9ca 100644
--- a/packages/client/lib/commands/ZINTER_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZINTER_WITHSCORES.ts
@@ -1,14 +1,15 @@
 import { Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZINTER from './ZINTER';
-import { transformSortedSetReply } from './generic-transformers';
+import { Tail, transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: ZINTER.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZINTER.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZINTER.transformArguments>) {
-    const redisArgs = ZINTER.transformArguments(...args);
-    redisArgs.push('WITHSCORES');
-    return redisArgs;
+  parseCommand(parser: CommandParser, ...args: Tail<Parameters<typeof ZINTER.parseCommand>>) {
+    ZINTER.parseCommand(parser, ...args);
+    parser.push('WITHSCORES');
   },
+  transformArguments(...args: Parameters<typeof ZINTER.transformArguments>) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZLEXCOUNT.spec.ts b/packages/client/lib/commands/ZLEXCOUNT.spec.ts
index d0a76075579..78c7411affd 100644
--- a/packages/client/lib/commands/ZLEXCOUNT.spec.ts
+++ b/packages/client/lib/commands/ZLEXCOUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZLEXCOUNT from './ZLEXCOUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('ZLEXCOUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZLEXCOUNT.transformArguments('key', '[a', '[b'),
+      parseArgs(ZLEXCOUNT, 'key', '[a', '[b'),
       ['ZLEXCOUNT', 'key', '[a', '[b']
     );
   });
diff --git a/packages/client/lib/commands/ZLEXCOUNT.ts b/packages/client/lib/commands/ZLEXCOUNT.ts
index 26c9e0d70ac..56f9a397030 100644
--- a/packages/client/lib/commands/ZLEXCOUNT.ts
+++ b/packages/client/lib/commands/ZLEXCOUNT.ts
@@ -1,19 +1,25 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: RedisArgument,
     max: RedisArgument
   ) {
-    return [
-      'ZLEXCOUNT',
-      key,
-      min,
-      max
-    ];
+    parser.setCachable();
+    parser.push('ZLEXCOUNT');
+    parser.pushKey(key);
+    parser.push(min);
+    parser.push(max);
   },
+  transformArguments(
+    key: RedisArgument,
+    min: RedisArgument,
+    max: RedisArgument
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZMPOP.spec.ts b/packages/client/lib/commands/ZMPOP.spec.ts
index 6335fca81cb..c15a53b7313 100644
--- a/packages/client/lib/commands/ZMPOP.spec.ts
+++ b/packages/client/lib/commands/ZMPOP.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZMPOP from './ZMPOP';
+import { parseArgs } from './generic-transformers';
 
 describe('ZMPOP', () => {
   testUtils.isVersionGreaterThanHook([7]);
@@ -8,14 +9,14 @@ describe('ZMPOP', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZMPOP.transformArguments('key', 'MIN'),
+        parseArgs(ZMPOP, 'key', 'MIN'),
         ['ZMPOP', '1', 'key', 'MIN']
       );
     });
 
     it('with count', () => {
       assert.deepEqual(
-        ZMPOP.transformArguments('key', 'MIN', {
+        parseArgs(ZMPOP, 'key', 'MIN', {
           COUNT: 2
         }),
         ['ZMPOP', '1', 'key', 'MIN', 'COUNT', '2']
diff --git a/packages/client/lib/commands/ZMPOP.ts b/packages/client/lib/commands/ZMPOP.ts
index 4cd8fc80276..dabad5c0bde 100644
--- a/packages/client/lib/commands/ZMPOP.ts
+++ b/packages/client/lib/commands/ZMPOP.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NullReply, TuplesReply, BlobStringReply, DoubleReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
-import { pushVariadicArgument, RedisVariadicArgument, SortedSetSide, transformSortedSetReply, transformDoubleReply } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument, SortedSetSide, transformSortedSetReply, transformDoubleReply, Tail } from './generic-transformers';
 
 export interface ZMPopOptions {
   COUNT?: number;
@@ -13,31 +14,30 @@ export type ZMPopRawReply = NullReply | TuplesReply<[
   ]>>
 ]>;
 
-export function transformZMPopArguments(
-  args: Array<RedisArgument>,
+export function parseZMPopArguments(
+  command: RedisArgument,
+  parser: CommandParser,
   keys: RedisVariadicArgument,
   side: SortedSetSide,
   options?: ZMPopOptions
 ) {
-  args = pushVariadicArgument(args, keys);
+  parser.push(command);
+  parser.pushKeysLength(keys);
 
-  args.push(side);
+  parser.push(side);
 
   if (options?.COUNT) {
-    args.push('COUNT', options.COUNT.toString());
+    parser.pushVariadic(['COUNT', options.COUNT.toString()]);
   }
-
-  return args;
 }
 
-export type ZMPopArguments = typeof transformZMPopArguments extends (_: any, ...args: infer T) => any ? T : never;
+export type ZMPopArguments = Tail<Tail<Parameters<typeof parseZMPopArguments>>>;
 
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(...args: ZMPopArguments) {
-    return transformZMPopArguments(['ZMPOP'], ...args);
-  },
+  parseCommand: parseZMPopArguments.bind(undefined, 'ZMPOP'),
+  transformArguments(...args: ZMPopArguments) { return [] },
   transformReply: {
     2(reply: UnwrapReply<Resp2Reply<ZMPopRawReply>>) {
       return reply === null ? null : {
diff --git a/packages/client/lib/commands/ZMSCORE.spec.ts b/packages/client/lib/commands/ZMSCORE.spec.ts
index 5035724b117..6c6d2946e00 100644
--- a/packages/client/lib/commands/ZMSCORE.spec.ts
+++ b/packages/client/lib/commands/ZMSCORE.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZMSCORE from './ZMSCORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZMSCORE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('ZMSCORE', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ZMSCORE.transformArguments('key', 'member'),
+        parseArgs(ZMSCORE, 'key', 'member'),
         ['ZMSCORE', 'key', 'member']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ZMSCORE.transformArguments('key', ['1', '2']),
+        parseArgs(ZMSCORE, 'key', ['1', '2']),
         ['ZMSCORE', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/ZMSCORE.ts b/packages/client/lib/commands/ZMSCORE.ts
index 983503983d5..502e8cec97c 100644
--- a/packages/client/lib/commands/ZMSCORE.ts
+++ b/packages/client/lib/commands/ZMSCORE.ts
@@ -1,15 +1,20 @@
 import { RedisArgument, ArrayReply, NullReply, BlobStringReply, DoubleReply, UnwrapReply, Command } from '../RESP/types';
-import { pushVariadicArguments, RedisVariadicArgument, transformNullableDoubleReply } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument, transformNullableDoubleReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisVariadicArgument) {
+    parser.setCachable();
+    parser.push('ZMSCORE');
+    parser.pushKey(key);
+    parser.pushVariadic(member);
+  },
   transformArguments(
     key: RedisArgument,
     member: RedisVariadicArgument
-  ) {
-    return pushVariadicArguments(['ZMSCORE', key], member);
-  },
+  ) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<ArrayReply<NullReply | BlobStringReply>>) => {
       return reply.map(transformNullableDoubleReply[2]);
diff --git a/packages/client/lib/commands/ZPOPMAX.spec.ts b/packages/client/lib/commands/ZPOPMAX.spec.ts
index 609ccb826b5..1796647df86 100644
--- a/packages/client/lib/commands/ZPOPMAX.spec.ts
+++ b/packages/client/lib/commands/ZPOPMAX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZPOPMAX from './ZPOPMAX';
+import { parseArgs } from './generic-transformers';
 
 describe('ZPOPMAX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZPOPMAX.transformArguments('key'),
+      parseArgs(ZPOPMAX, 'key'),
       ['ZPOPMAX', 'key']
     );
   });
diff --git a/packages/client/lib/commands/ZPOPMAX.ts b/packages/client/lib/commands/ZPOPMAX.ts
index 012ba1fbb52..09b995a272c 100644
--- a/packages/client/lib/commands/ZPOPMAX.ts
+++ b/packages/client/lib/commands/ZPOPMAX.ts
@@ -1,11 +1,14 @@
 import { RedisArgument, TuplesReply, BlobStringReply, DoubleReply, UnwrapReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument) {
-    return ['ZPOPMAX', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('ZPOPMAX');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<TuplesReply<[] | [BlobStringReply, BlobStringReply]>>) => {
       if (reply.length === 0) return null;
diff --git a/packages/client/lib/commands/ZPOPMAX_COUNT.spec.ts b/packages/client/lib/commands/ZPOPMAX_COUNT.spec.ts
index b653b1f3f1a..dd9d85dbd36 100644
--- a/packages/client/lib/commands/ZPOPMAX_COUNT.spec.ts
+++ b/packages/client/lib/commands/ZPOPMAX_COUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZPOPMAX_COUNT from './ZPOPMAX_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('ZPOPMAX COUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZPOPMAX_COUNT.transformArguments('key', 1),
+      parseArgs(ZPOPMAX_COUNT, 'key', 1),
       ['ZPOPMAX', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZPOPMAX_COUNT.ts b/packages/client/lib/commands/ZPOPMAX_COUNT.ts
index 00d39536ae1..b3f313f04ae 100644
--- a/packages/client/lib/commands/ZPOPMAX_COUNT.ts
+++ b/packages/client/lib/commands/ZPOPMAX_COUNT.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['ZPOPMAX', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('ZPOPMAX');
+    parser.pushKey(key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZPOPMIN.spec.ts b/packages/client/lib/commands/ZPOPMIN.spec.ts
index 0b2c57d28b9..653a4e70a92 100644
--- a/packages/client/lib/commands/ZPOPMIN.spec.ts
+++ b/packages/client/lib/commands/ZPOPMIN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZPOPMIN from './ZPOPMIN';
+import { parseArgs } from './generic-transformers';
 
 describe('ZPOPMIN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZPOPMIN.transformArguments('key'),
+      parseArgs(ZPOPMIN, 'key'),
       ['ZPOPMIN', 'key']
     );
   });
diff --git a/packages/client/lib/commands/ZPOPMIN.ts b/packages/client/lib/commands/ZPOPMIN.ts
index b9da85cc974..3c4bb4167ac 100644
--- a/packages/client/lib/commands/ZPOPMIN.ts
+++ b/packages/client/lib/commands/ZPOPMIN.ts
@@ -1,11 +1,14 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZPOPMAX from './ZPOPMAX';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument) {
-    return ['ZPOPMIN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('ZPOPMIN');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: ZPOPMAX.transformReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZPOPMIN_COUNT.spec.ts b/packages/client/lib/commands/ZPOPMIN_COUNT.spec.ts
index fa3d9e2a975..126a3cc1e9a 100644
--- a/packages/client/lib/commands/ZPOPMIN_COUNT.spec.ts
+++ b/packages/client/lib/commands/ZPOPMIN_COUNT.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZPOPMIN_COUNT from './ZPOPMIN_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('ZPOPMIN COUNT', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZPOPMIN_COUNT.transformArguments('key', 1),
+      parseArgs(ZPOPMIN_COUNT, 'key', 1),
       ['ZPOPMIN', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZPOPMIN_COUNT.ts b/packages/client/lib/commands/ZPOPMIN_COUNT.ts
index 2433686da56..1fea516cbc4 100644
--- a/packages/client/lib/commands/ZPOPMIN_COUNT.ts
+++ b/packages/client/lib/commands/ZPOPMIN_COUNT.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, count: number) {
-    return ['ZPOPMIN', key, count.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    parser.push('ZPOPMIN');
+    parser.pushKey(key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANDMEMBER.spec.ts b/packages/client/lib/commands/ZRANDMEMBER.spec.ts
index 519850f5eff..a25ea79f8e1 100644
--- a/packages/client/lib/commands/ZRANDMEMBER.spec.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANDMEMBER from './ZRANDMEMBER';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANDMEMBER', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ZRANDMEMBER.transformArguments('key'),
+      parseArgs(ZRANDMEMBER, 'key'),
       ['ZRANDMEMBER', 'key']
     );
   });
diff --git a/packages/client/lib/commands/ZRANDMEMBER.ts b/packages/client/lib/commands/ZRANDMEMBER.ts
index 449eb281c66..46ea33ef012 100644
--- a/packages/client/lib/commands/ZRANDMEMBER.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['ZRANDMEMBER', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('ZRANDMEMBER');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANDMEMBER_COUNT.spec.ts b/packages/client/lib/commands/ZRANDMEMBER_COUNT.spec.ts
index 2d0f4b9ced8..eee0d454975 100644
--- a/packages/client/lib/commands/ZRANDMEMBER_COUNT.spec.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER_COUNT.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANDMEMBER_COUNT from './ZRANDMEMBER_COUNT';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANDMEMBER COUNT', () => {
   testUtils.isVersionGreaterThanHook([6, 2, 5]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ZRANDMEMBER_COUNT.transformArguments('key', 1),
+      parseArgs(ZRANDMEMBER_COUNT, 'key', 1),
       ['ZRANDMEMBER', 'key', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZRANDMEMBER_COUNT.ts b/packages/client/lib/commands/ZRANDMEMBER_COUNT.ts
index 89b921f007a..3a1cafceaaa 100644
--- a/packages/client/lib/commands/ZRANDMEMBER_COUNT.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER_COUNT.ts
@@ -1,13 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZRANDMEMBER from './ZRANDMEMBER';
 
 export default {
   FIRST_KEY_INDEX: ZRANDMEMBER.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZRANDMEMBER.IS_READ_ONLY,
-  transformArguments(key: RedisArgument, count: number) {
-    const args = ZRANDMEMBER.transformArguments(key);
-    args.push(count.toString());
-    return args;
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    ZRANDMEMBER.parseCommand(parser, key);
+    parser.push(count.toString());
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts b/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts
index aeeea3f6e71..3be3b92aeef 100644
--- a/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANDMEMBER_COUNT_WITHSCORES from './ZRANDMEMBER_COUNT_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANDMEMBER COUNT WITHSCORES', () => {
   testUtils.isVersionGreaterThanHook([6, 2, 5]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ZRANDMEMBER_COUNT_WITHSCORES.transformArguments('key', 1),
+      parseArgs(ZRANDMEMBER_COUNT_WITHSCORES, 'key', 1),
       ['ZRANDMEMBER', 'key', '1', 'WITHSCORES']
     );
   });
diff --git a/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.ts b/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.ts
index 14c28d4b6c6..fb5de8aeed6 100644
--- a/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.ts
@@ -1,14 +1,15 @@
 import { Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZRANDMEMBER_COUNT from './ZRANDMEMBER_COUNT';
 import { transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: ZRANDMEMBER_COUNT.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZRANDMEMBER_COUNT.IS_READ_ONLY,
-  transformArguments(key: RedisArgument, count: number) {
-    const args = ZRANDMEMBER_COUNT.transformArguments(key, count);
-    args.push('WITHSCORES');
-    return args;
+  parseCommand(parser: CommandParser, key: RedisArgument, count: number) {
+    ZRANDMEMBER_COUNT.parseCommand(parser, key, count);
+    parser.push('WITHSCORES');
   },
+  transformArguments(key: RedisArgument, count: number) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGE.spec.ts b/packages/client/lib/commands/ZRANGE.spec.ts
index db940062b2f..a780e4ef613 100644
--- a/packages/client/lib/commands/ZRANGE.spec.ts
+++ b/packages/client/lib/commands/ZRANGE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGE from './ZRANGE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1),
+        parseArgs(ZRANGE, 'src', 0, 1),
         ['ZRANGE', 'src', '0', '1']
       );
     });
 
     it('with BYSCORE', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE, 'src', 0, 1, {
           BY: 'SCORE'
         }),
         ['ZRANGE', 'src', '0', '1', 'BYSCORE']
@@ -22,7 +23,7 @@ describe('ZRANGE', () => {
 
     it('with BYLEX', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE, 'src', 0, 1, {
           BY: 'LEX'
         }),
         ['ZRANGE', 'src', '0', '1', 'BYLEX']
@@ -31,7 +32,7 @@ describe('ZRANGE', () => {
 
     it('with REV', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE, 'src', 0, 1, {
           REV: true
         }),
         ['ZRANGE', 'src', '0', '1', 'REV']
@@ -40,7 +41,7 @@ describe('ZRANGE', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE, 'src', 0, 1, {
           LIMIT: {
             offset: 0,
             count: 1
@@ -52,7 +53,7 @@ describe('ZRANGE', () => {
 
     it('with BY & REV & LIMIT', () => {
       assert.deepEqual(
-        ZRANGE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE, 'src', 0, 1, {
           BY: 'SCORE',
           REV: true,
           LIMIT: {
diff --git a/packages/client/lib/commands/ZRANGE.ts b/packages/client/lib/commands/ZRANGE.ts
index 557044b67da..a43c51e07bf 100644
--- a/packages/client/lib/commands/ZRANGE.ts
+++ b/packages/client/lib/commands/ZRANGE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export interface ZRangeOptions {
@@ -10,45 +11,61 @@ export interface ZRangeOptions {
   };
 }
 
+export function zRangeArgument(
+  min: RedisArgument | number,
+  max: RedisArgument | number,
+  options?: ZRangeOptions
+) {
+  const args = [
+    transformStringDoubleArgument(min),
+    transformStringDoubleArgument(max)
+  ]
+
+  switch (options?.BY) {
+    case 'SCORE':
+      args.push('BYSCORE');
+      break;
+
+    case 'LEX':
+      args.push('BYLEX');
+      break;
+  }
+
+  if (options?.REV) {
+    args.push('REV');
+  }
+
+  if (options?.LIMIT) {
+    args.push(
+      'LIMIT',
+      options.LIMIT.offset.toString(),
+      options.LIMIT.count.toString()
+    );
+  }
+
+  return args;
+}
+
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: RedisArgument | number,
     max: RedisArgument | number,
     options?: ZRangeOptions
   ) {
-    const args = [
-      'ZRANGE',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
-
-    switch (options?.BY) {
-      case 'SCORE':
-        args.push('BYSCORE');
-        break;
-
-      case 'LEX':
-        args.push('BYLEX');
-        break;
-    }
-
-    if (options?.REV) {
-      args.push('REV');
-    }
-
-    if (options?.LIMIT) {
-      args.push(
-        'LIMIT',
-        options.LIMIT.offset.toString(),
-        options.LIMIT.count.toString()
-      );
-    }
-
-    return args;
+    parser.setCachable();
+    parser.push('ZRANGE');
+    parser.pushKey(key);
+    parser.pushVariadic(zRangeArgument(min, max, options))
   },
+  transformArguments(
+    key: RedisArgument,
+    min: RedisArgument | number,
+    max: RedisArgument | number,
+    options?: ZRangeOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGEBYLEX.spec.ts b/packages/client/lib/commands/ZRANGEBYLEX.spec.ts
index f3f6f4bc0e5..942e184661a 100644
--- a/packages/client/lib/commands/ZRANGEBYLEX.spec.ts
+++ b/packages/client/lib/commands/ZRANGEBYLEX.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGEBYLEX from './ZRANGEBYLEX';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGEBYLEX', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGEBYLEX.transformArguments('src', '-', '+'),
+        parseArgs(ZRANGEBYLEX, 'src', '-', '+'),
         ['ZRANGEBYLEX', 'src', '-', '+']
       );
     });
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGEBYLEX.transformArguments('src', '-', '+', {
+        parseArgs(ZRANGEBYLEX, 'src', '-', '+', {
           LIMIT: {
             offset: 0,
             count: 1
diff --git a/packages/client/lib/commands/ZRANGEBYLEX.ts b/packages/client/lib/commands/ZRANGEBYLEX.ts
index afe7718f3c3..2184ccb72ad 100644
--- a/packages/client/lib/commands/ZRANGEBYLEX.ts
+++ b/packages/client/lib/commands/ZRANGEBYLEX.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export interface ZRangeByLexOptions {
@@ -11,24 +12,32 @@ export interface ZRangeByLexOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: RedisArgument,
     max: RedisArgument,
     options?: ZRangeByLexOptions
   ) {
-    const args = [
-      'ZRANGEBYLEX',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.setCachable();
+    parser.push('ZRANGEBYLEX');
+    parser.pushKey(key);
+    parser.pushVariadic(
+      [
+        transformStringDoubleArgument(min),
+        transformStringDoubleArgument(max),
+      ]
+    );
 
     if (options?.LIMIT) {
-      args.push('LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    min: RedisArgument,
+    max: RedisArgument,
+    options?: ZRangeByLexOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGEBYSCORE.spec.ts b/packages/client/lib/commands/ZRANGEBYSCORE.spec.ts
index 61267ea7f2f..364882f21a9 100644
--- a/packages/client/lib/commands/ZRANGEBYSCORE.spec.ts
+++ b/packages/client/lib/commands/ZRANGEBYSCORE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGEBYSCORE from './ZRANGEBYSCORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGEBYSCORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGEBYSCORE.transformArguments('src', 0, 1),
+        parseArgs(ZRANGEBYSCORE, 'src', 0, 1),
         ['ZRANGEBYSCORE', 'src', '0', '1']
       );
     });
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGEBYSCORE.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGEBYSCORE, 'src', 0, 1, {
           LIMIT: {
             offset: 0,
             count: 1
diff --git a/packages/client/lib/commands/ZRANGEBYSCORE.ts b/packages/client/lib/commands/ZRANGEBYSCORE.ts
index e54c96380de..b388ea60ef6 100644
--- a/packages/client/lib/commands/ZRANGEBYSCORE.ts
+++ b/packages/client/lib/commands/ZRANGEBYSCORE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export interface ZRangeByScoreOptions {
@@ -13,24 +14,32 @@ export declare function transformReply(): Array<RedisArgument>;
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: string | number,
     max: string | number,
     options?: ZRangeByScoreOptions
   ) {
-    const args = [
-      'ZRANGEBYSCORE',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.setCachable();
+    parser.push('ZRANGEBYSCORE');
+    parser.pushKey(key);
+    parser.pushVariadic(
+      [
+        transformStringDoubleArgument(min),
+        transformStringDoubleArgument(max)
+      ]
+    );
 
     if (options?.LIMIT) {
-      args.push('LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    min: string | number,
+    max: string | number,
+    options?: ZRangeByScoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.spec.ts b/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.spec.ts
index e70a97b0372..191eaa4e34f 100644
--- a/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGEBYSCORE_WITHSCORES from './ZRANGEBYSCORE_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGEBYSCORE WITHSCORES', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGEBYSCORE_WITHSCORES.transformArguments('src', 0, 1),
+        parseArgs(ZRANGEBYSCORE_WITHSCORES, 'src', 0, 1),
         ['ZRANGEBYSCORE', 'src', '0', '1', 'WITHSCORES']
       );
     });
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGEBYSCORE_WITHSCORES.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGEBYSCORE_WITHSCORES, 'src', 0, 1, {
           LIMIT: {
             offset: 0,
             count: 1
diff --git a/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.ts b/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.ts
index bfbe09c6e26..9e5a1bd5356 100644
--- a/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZRANGEBYSCORE_WITHSCORES.ts
@@ -5,10 +5,10 @@ import { transformSortedSetReply } from './generic-transformers';
 export default {
   FIRST_KEY_INDEX: ZRANGEBYSCORE.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZRANGEBYSCORE.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZRANGEBYSCORE.transformArguments>) {
-    const redisArgs = ZRANGEBYSCORE.transformArguments(...args);
-    redisArgs.push('WITHSCORES');
-    return redisArgs;
+  parseCommand(...args: Parameters<typeof ZRANGEBYSCORE.parseCommand>) {
+    ZRANGEBYSCORE.parseCommand(...args);
+    args[0].push('WITHSCORES');
   },
+  transformArguments(...args: Parameters<typeof ZRANGEBYSCORE.transformArguments>) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGESTORE.spec.ts b/packages/client/lib/commands/ZRANGESTORE.spec.ts
index 51315d3463b..c9708efd6fd 100644
--- a/packages/client/lib/commands/ZRANGESTORE.spec.ts
+++ b/packages/client/lib/commands/ZRANGESTORE.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGESTORE from './ZRANGESTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGESTORE', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,14 +9,14 @@ describe('ZRANGESTORE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1),
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1),
         ['ZRANGESTORE', 'destination', 'source', '0', '1']
       );
     });
 
     it('with BYSCORE', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1, {
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1, {
           BY: 'SCORE'
         }),
         ['ZRANGESTORE', 'destination', 'source', '0', '1', 'BYSCORE']
@@ -24,7 +25,7 @@ describe('ZRANGESTORE', () => {
 
     it('with BYLEX', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1, {
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1, {
           BY: 'LEX'
         }),
         ['ZRANGESTORE', 'destination', 'source', '0', '1', 'BYLEX']
@@ -33,7 +34,7 @@ describe('ZRANGESTORE', () => {
 
     it('with REV', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1, {
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1, {
           REV: true
         }),
         ['ZRANGESTORE', 'destination', 'source', '0', '1', 'REV']
@@ -42,7 +43,7 @@ describe('ZRANGESTORE', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1, {
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1, {
           LIMIT: {
             offset: 0,
             count: 1
@@ -54,7 +55,7 @@ describe('ZRANGESTORE', () => {
 
     it('with BY & REV & LIMIT', () => {
       assert.deepEqual(
-        ZRANGESTORE.transformArguments('destination', 'source', 0, 1, {
+        parseArgs(ZRANGESTORE, 'destination', 'source', 0, 1, {
           BY: 'SCORE',
           REV: true,
           LIMIT: {
diff --git a/packages/client/lib/commands/ZRANGESTORE.ts b/packages/client/lib/commands/ZRANGESTORE.ts
index 96f10120b87..4f6761eb8de 100644
--- a/packages/client/lib/commands/ZRANGESTORE.ts
+++ b/packages/client/lib/commands/ZRANGESTORE.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export interface ZRangeStoreOptions {
@@ -13,40 +14,43 @@ export interface ZRangeStoreOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     destination: RedisArgument,
     source: RedisArgument,
     min: RedisArgument | number,
     max: RedisArgument | number,
     options?: ZRangeStoreOptions
   ) {
-    const args = [
-      'ZRANGESTORE',
-      destination,
-      source,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.push('ZRANGESTORE');
+    parser.pushKey(destination);
+    parser.pushKey(source);
+    parser.pushVariadic([transformStringDoubleArgument(min), transformStringDoubleArgument(max)]);
 
     switch (options?.BY) {
       case 'SCORE':
-        args.push('BYSCORE');
+        parser.push('BYSCORE');
         break;
 
       case 'LEX':
-        args.push('BYLEX');
+        parser.push('BYLEX');
         break;
     }
 
     if (options?.REV) {
-      args.push('REV');
+      parser.push('REV');
     }
 
     if (options?.LIMIT) {
-      args.push('LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString());
+      parser.pushVariadic(['LIMIT', options.LIMIT.offset.toString(), options.LIMIT.count.toString()]);
     }
-
-    return args;
   },
+  transformArguments(
+    destination: RedisArgument,
+    source: RedisArgument,
+    min: RedisArgument | number,
+    max: RedisArgument | number,
+    options?: ZRangeStoreOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANGE_WITHSCORES.spec.ts b/packages/client/lib/commands/ZRANGE_WITHSCORES.spec.ts
index 038c150a675..e3009a6eadb 100644
--- a/packages/client/lib/commands/ZRANGE_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZRANGE_WITHSCORES.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANGE_WITHSCORES from './ZRANGE_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANGE WITHSCORES', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ZRANGE_WITHSCORES.transformArguments('src', 0, 1),
+        parseArgs(ZRANGE_WITHSCORES, 'src', 0, 1),
         ['ZRANGE', 'src', '0', '1', 'WITHSCORES']
       );
     });
 
     it('with BY', () => {
       assert.deepEqual(
-        ZRANGE_WITHSCORES.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE_WITHSCORES, 'src', 0, 1, {
           BY: 'SCORE'
         }),
         ['ZRANGE', 'src', '0', '1', 'BYSCORE', 'WITHSCORES']
@@ -22,7 +23,7 @@ describe('ZRANGE WITHSCORES', () => {
 
     it('with REV', () => {
       assert.deepEqual(
-        ZRANGE_WITHSCORES.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE_WITHSCORES, 'src', 0, 1, {
           REV: true
         }),
         ['ZRANGE', 'src', '0', '1', 'REV', 'WITHSCORES']
@@ -31,7 +32,7 @@ describe('ZRANGE WITHSCORES', () => {
 
     it('with LIMIT', () => {
       assert.deepEqual(
-        ZRANGE_WITHSCORES.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE_WITHSCORES, 'src', 0, 1, {
           LIMIT: {
             offset: 0,
             count: 1
@@ -43,7 +44,7 @@ describe('ZRANGE WITHSCORES', () => {
 
     it('with BY & REV & LIMIT', () => {
       assert.deepEqual(
-        ZRANGE_WITHSCORES.transformArguments('src', 0, 1, {
+        parseArgs(ZRANGE_WITHSCORES, 'src', 0, 1, {
           BY: 'SCORE',
           REV: true,
           LIMIT: {
diff --git a/packages/client/lib/commands/ZRANGE_WITHSCORES.ts b/packages/client/lib/commands/ZRANGE_WITHSCORES.ts
index cfa90e99ea4..138fb7f9b81 100644
--- a/packages/client/lib/commands/ZRANGE_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZRANGE_WITHSCORES.ts
@@ -5,11 +5,11 @@ import { transformSortedSetReply } from './generic-transformers';
 export default {
   FIRST_KEY_INDEX: ZRANGE.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZRANGE.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZRANGE.transformArguments>) {
-    const redisArgs = ZRANGE.transformArguments(...args);
-    redisArgs.push('WITHSCORES');
-    return redisArgs;
+  parseCommand(...args: Parameters<typeof ZRANGE.parseCommand>) {
+    ZRANGE.parseCommand(...args);
+    args[0].push('WITHSCORES');
   },
+  transformArguments(...args: Parameters<typeof ZRANGE.transformArguments>) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
 
diff --git a/packages/client/lib/commands/ZRANK.spec.ts b/packages/client/lib/commands/ZRANK.spec.ts
index 9341709bda3..480f75f66e1 100644
--- a/packages/client/lib/commands/ZRANK.spec.ts
+++ b/packages/client/lib/commands/ZRANK.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANK from './ZRANK';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANK', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZRANK.transformArguments('key', 'member'),
+      parseArgs(ZRANK, 'key', 'member'),
       ['ZRANK', 'key', 'member']
     );
   });
diff --git a/packages/client/lib/commands/ZRANK.ts b/packages/client/lib/commands/ZRANK.ts
index 11184c0a28f..1ed9e4a9cb3 100644
--- a/packages/client/lib/commands/ZRANK.ts
+++ b/packages/client/lib/commands/ZRANK.ts
@@ -1,10 +1,15 @@
 import { RedisArgument, NumberReply, NullReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, member: RedisArgument) {
-    return ['ZRANK', key, member];
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisArgument) {
+    parser.setCachable();
+    parser.push('ZRANK');
+    parser.pushKey(key);
+    parser.push(member);
   },
+  transformArguments(key: RedisArgument, member: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZRANK_WITHSCORE.spec.ts b/packages/client/lib/commands/ZRANK_WITHSCORE.spec.ts
index b571e0f7071..9fa7cb1f6fd 100644
--- a/packages/client/lib/commands/ZRANK_WITHSCORE.spec.ts
+++ b/packages/client/lib/commands/ZRANK_WITHSCORE.spec.ts
@@ -1,13 +1,14 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZRANK_WITHSCORE from './ZRANK_WITHSCORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZRANK WITHSCORE', () => {
   testUtils.isVersionGreaterThanHook([7, 2]);
 
   it('transformArguments', () => {
     assert.deepEqual(
-      ZRANK_WITHSCORE.transformArguments('key', 'member'),
+      parseArgs(ZRANK_WITHSCORE, 'key', 'member'),
       ['ZRANK', 'key', 'member', 'WITHSCORE']
     );
   });
diff --git a/packages/client/lib/commands/ZRANK_WITHSCORE.ts b/packages/client/lib/commands/ZRANK_WITHSCORE.ts
index 39c788535e3..8e984cbb0e8 100644
--- a/packages/client/lib/commands/ZRANK_WITHSCORE.ts
+++ b/packages/client/lib/commands/ZRANK_WITHSCORE.ts
@@ -4,11 +4,11 @@ import ZRANK from './ZRANK';
 export default {
   FIRST_KEY_INDEX: ZRANK.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZRANK.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZRANK.transformArguments>) {
-    const redisArgs = ZRANK.transformArguments(...args);
-    redisArgs.push('WITHSCORE');
-    return redisArgs;
+  parseCommand(...args: Parameters<typeof ZRANK.parseCommand>) {
+    ZRANK.parseCommand(...args);
+    args[0].push('WITHSCORE');
   },
+  transformArguments(...args: Parameters<typeof ZRANK.transformArguments>) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<NullReply | TuplesReply<[NumberReply, BlobStringReply]>>) => {
       if (reply === null) return null;
diff --git a/packages/client/lib/commands/ZREM.spec.ts b/packages/client/lib/commands/ZREM.spec.ts
index 4b203c9f4eb..ac65b3d0139 100644
--- a/packages/client/lib/commands/ZREM.spec.ts
+++ b/packages/client/lib/commands/ZREM.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZREM from './ZREM';
+import { parseArgs } from './generic-transformers';
 
 describe('ZREM', () => {
   describe('transformArguments', () => {
     it('string', () => {
       assert.deepEqual(
-        ZREM.transformArguments('key', 'member'),
+        parseArgs(ZREM, 'key', 'member'),
         ['ZREM', 'key', 'member']
       );
     });
 
     it('array', () => {
       assert.deepEqual(
-        ZREM.transformArguments('key', ['1', '2']),
+        parseArgs(ZREM, 'key', ['1', '2']),
         ['ZREM', 'key', '1', '2']
       );
     });
diff --git a/packages/client/lib/commands/ZREM.ts b/packages/client/lib/commands/ZREM.ts
index 54f55841fce..d55f9a34678 100644
--- a/packages/client/lib/commands/ZREM.ts
+++ b/packages/client/lib/commands/ZREM.ts
@@ -1,14 +1,19 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { RedisVariadicArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     member: RedisVariadicArgument
   ) {
-    return pushVariadicArguments(['ZREM', key], member);
+    parser.push('ZREM');
+    parser.pushKey(key);
+    parser.pushVariadic(member);
   },
+  transformArguments(key: RedisArgument, member: RedisVariadicArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZREMRANGEBYLEX.spec.ts b/packages/client/lib/commands/ZREMRANGEBYLEX.spec.ts
index 9f29c3cdcf7..b141b7679ee 100644
--- a/packages/client/lib/commands/ZREMRANGEBYLEX.spec.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYLEX.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZREMRANGEBYLEX from './ZREMRANGEBYLEX';
+import { parseArgs } from './generic-transformers';
 
 describe('ZREMRANGEBYLEX', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZREMRANGEBYLEX.transformArguments('key', '[a', '[b'),
+      parseArgs(ZREMRANGEBYLEX, 'key', '[a', '[b'),
       ['ZREMRANGEBYLEX', 'key', '[a', '[b']
     );
   });
diff --git a/packages/client/lib/commands/ZREMRANGEBYLEX.ts b/packages/client/lib/commands/ZREMRANGEBYLEX.ts
index e3cd7013ac2..2fc4b3cfecf 100644
--- a/packages/client/lib/commands/ZREMRANGEBYLEX.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYLEX.ts
@@ -1,20 +1,20 @@
 import { NumberReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: RedisArgument | number,
     max: RedisArgument | number
   ) {
-    return [
-      'ZREMRANGEBYLEX',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.push('ZREMRANGEBYLEX');
+    parser.pushKey(key);
+    parser.pushVariadic([transformStringDoubleArgument(min), transformStringDoubleArgument(max)]);
   },
+  transformArguments(key: RedisArgument, min: RedisArgument | number, max: RedisArgument | number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZREMRANGEBYRANK.spec.ts b/packages/client/lib/commands/ZREMRANGEBYRANK.spec.ts
index 12627083e1a..19f54466c20 100644
--- a/packages/client/lib/commands/ZREMRANGEBYRANK.spec.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYRANK.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZREMRANGEBYRANK from './ZREMRANGEBYRANK';
+import { parseArgs } from './generic-transformers';
 
 describe('ZREMRANGEBYRANK', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZREMRANGEBYRANK.transformArguments('key', 0, 1),
+      parseArgs(ZREMRANGEBYRANK, 'key', 0, 1),
       ['ZREMRANGEBYRANK', 'key', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZREMRANGEBYRANK.ts b/packages/client/lib/commands/ZREMRANGEBYRANK.ts
index 986de33060e..54479452ca1 100644
--- a/packages/client/lib/commands/ZREMRANGEBYRANK.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYRANK.ts
@@ -1,13 +1,19 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     start: number,
-    stop: number) {
-    return ['ZREMRANGEBYRANK', key, start.toString(), stop.toString()];
+    stop: number
+  ) {      
+    parser.push('ZREMRANGEBYRANK');
+    parser.pushKey(key);
+    parser.pushVariadic([start.toString(), stop.toString()]);
   },
+  transformArguments(key: RedisArgument, start: number, stop: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZREMRANGEBYSCORE.spec.ts b/packages/client/lib/commands/ZREMRANGEBYSCORE.spec.ts
index fb3ba4e718c..856692ef8f5 100644
--- a/packages/client/lib/commands/ZREMRANGEBYSCORE.spec.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYSCORE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import ZREMRANGEBYSCORE from './ZREMRANGEBYSCORE';
 
 describe('ZREMRANGEBYSCORE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZREMRANGEBYSCORE.transformArguments('key', 0, 1),
+      parseArgs(ZREMRANGEBYSCORE, 'key', 0, 1),
       ['ZREMRANGEBYSCORE', 'key', '0', '1']
     );
   });
diff --git a/packages/client/lib/commands/ZREMRANGEBYSCORE.ts b/packages/client/lib/commands/ZREMRANGEBYSCORE.ts
index 7050f2627a7..aee48f435da 100644
--- a/packages/client/lib/commands/ZREMRANGEBYSCORE.ts
+++ b/packages/client/lib/commands/ZREMRANGEBYSCORE.ts
@@ -1,20 +1,20 @@
 import { RedisArgument, NumberReply, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformStringDoubleArgument } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     min: RedisArgument | number,
     max: RedisArgument | number,
   ) {
-    return [
-      'ZREMRANGEBYSCORE',
-      key,
-      transformStringDoubleArgument(min),
-      transformStringDoubleArgument(max)
-    ];
+    parser.push('ZREMRANGEBYSCORE');
+    parser.pushKey(key);
+    parser.pushVariadic([transformStringDoubleArgument(min), transformStringDoubleArgument(max)]);
   },
+  transformArguments(key: RedisArgument,  min: RedisArgument | number, max: RedisArgument | number) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZREVRANK.spec.ts b/packages/client/lib/commands/ZREVRANK.spec.ts
index 418773b6003..c89f528eb1c 100644
--- a/packages/client/lib/commands/ZREVRANK.spec.ts
+++ b/packages/client/lib/commands/ZREVRANK.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import ZREVRANK from './ZREVRANK';
 
 describe('ZREVRANK', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZREVRANK.transformArguments('key', 'member'),
+      parseArgs(ZREVRANK, 'key', 'member'),
       ['ZREVRANK', 'key', 'member']
     );
   });
diff --git a/packages/client/lib/commands/ZREVRANK.ts b/packages/client/lib/commands/ZREVRANK.ts
index 3bf52d21de5..6ce22fff4b5 100644
--- a/packages/client/lib/commands/ZREVRANK.ts
+++ b/packages/client/lib/commands/ZREVRANK.ts
@@ -1,10 +1,15 @@
 import { NumberReply, NullReply, Command, RedisArgument } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, member: RedisArgument) {
-    return ['ZREVRANK', key, member];
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisArgument) {
+    parser.setCachable();
+    parser.push('ZREVRANK');
+    parser.pushKey(key);
+    parser.push(member);
   },
+  transformArguments(key: RedisArgument, member: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZSCAN.spec.ts b/packages/client/lib/commands/ZSCAN.spec.ts
index ebeaad2a4d0..f8064aea41e 100644
--- a/packages/client/lib/commands/ZSCAN.spec.ts
+++ b/packages/client/lib/commands/ZSCAN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
+import { parseArgs } from './generic-transformers';
 import ZSCAN from './ZSCAN';
 
 describe('ZSCAN', () => {
   describe('transformArguments', () => {
     it('cusror only', () => {
       assert.deepEqual(
-        ZSCAN.transformArguments('key', '0'),
+        parseArgs(ZSCAN, 'key', '0'),
         ['ZSCAN', 'key', '0']
       );
     });
 
     it('with MATCH', () => {
       assert.deepEqual(
-        ZSCAN.transformArguments('key', '0', {
+        parseArgs(ZSCAN, 'key', '0', {
           MATCH: 'pattern'
         }),
         ['ZSCAN', 'key', '0', 'MATCH', 'pattern']
@@ -22,7 +23,7 @@ describe('ZSCAN', () => {
 
     it('with COUNT', () => {
       assert.deepEqual(
-        ZSCAN.transformArguments('key', '0', {
+        parseArgs(ZSCAN, 'key', '0', {
           COUNT: 1
         }),
         ['ZSCAN', 'key', '0', 'COUNT', '1']
@@ -31,7 +32,7 @@ describe('ZSCAN', () => {
 
     it('with MATCH & COUNT', () => {
       assert.deepEqual(
-        ZSCAN.transformArguments('key', '0', {
+        parseArgs(ZSCAN, 'key', '0', {
           MATCH: 'pattern',
           COUNT: 1
         }),
diff --git a/packages/client/lib/commands/ZSCAN.ts b/packages/client/lib/commands/ZSCAN.ts
index 853cdf098f6..3052c8bf6e6 100644
--- a/packages/client/lib/commands/ZSCAN.ts
+++ b/packages/client/lib/commands/ZSCAN.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { ScanCommonOptions, pushScanArguments } from './SCAN';
+import { CommandParser } from '../client/parser';
+import { ScanCommonOptions, parseScanArguments } from './SCAN';
 import { transformSortedSetReply } from './generic-transformers';
 
 export interface HScanEntry {
@@ -10,13 +11,21 @@ export interface HScanEntry {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     cursor: RedisArgument,
     options?: ScanCommonOptions
   ) {
-    return pushScanArguments(['ZSCAN', key], cursor, options);
+    parser.push('ZSCAN');
+    parser.pushKey(key);
+    parseScanArguments(parser, cursor, options);
   },
+  transformArguments(
+    key: RedisArgument,
+    cursor: RedisArgument,
+    options?: ScanCommonOptions
+  ) { return [] },
   transformReply([cursor, rawMembers]: [BlobStringReply, ArrayReply<BlobStringReply>]) {
     return {
       cursor,
diff --git a/packages/client/lib/commands/ZSCORE.spec.ts b/packages/client/lib/commands/ZSCORE.spec.ts
index 3d8df6640c8..4229ab7aac0 100644
--- a/packages/client/lib/commands/ZSCORE.spec.ts
+++ b/packages/client/lib/commands/ZSCORE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZSCORE from './ZSCORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZSCORE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ZSCORE.transformArguments('key', 'member'),
+      parseArgs(ZSCORE, 'key', 'member'),
       ['ZSCORE', 'key', 'member']
     );
   });
diff --git a/packages/client/lib/commands/ZSCORE.ts b/packages/client/lib/commands/ZSCORE.ts
index 0d3db752e1c..f67bc771014 100644
--- a/packages/client/lib/commands/ZSCORE.ts
+++ b/packages/client/lib/commands/ZSCORE.ts
@@ -1,12 +1,17 @@
 
 import { RedisArgument, Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import { transformNullableDoubleReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, member: RedisArgument) {
-    return ['ZSCORE', key, member];
+  parseCommand(parser: CommandParser, key: RedisArgument, member: RedisArgument) {
+    parser.setCachable();
+    parser.push('ZSCORE');
+    parser.pushKey(key);
+    parser.push(member);
   },
+  transformArguments(key: RedisArgument, member: RedisArgument) { return [] },
   transformReply: transformNullableDoubleReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZUNION.spec.ts b/packages/client/lib/commands/ZUNION.spec.ts
index f66bb7abc63..b4dbb4de603 100644
--- a/packages/client/lib/commands/ZUNION.spec.ts
+++ b/packages/client/lib/commands/ZUNION.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZUNION from './ZUNION';
+import { parseArgs } from './generic-transformers';
 
 describe('ZUNION', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,21 +9,21 @@ describe('ZUNION', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZUNION.transformArguments('key'),
+        parseArgs(ZUNION, 'key'),
         ['ZUNION', '1', 'key']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZUNION.transformArguments(['1', '2']),
+        parseArgs(ZUNION, ['1', '2']),
         ['ZUNION', '2', '1', '2']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZUNION.transformArguments({
+        parseArgs(ZUNION, {
           key: 'key',
           weight: 1
         }),
@@ -32,7 +33,7 @@ describe('ZUNION', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZUNION.transformArguments([{
+        parseArgs(ZUNION, [{
           key: 'a',
           weight: 1
         }, {
@@ -45,7 +46,7 @@ describe('ZUNION', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZUNION.transformArguments('key', {
+        parseArgs(ZUNION, 'key', {
           AGGREGATE: 'SUM'
         }),
         ['ZUNION', '1', 'key', 'AGGREGATE', 'SUM']
diff --git a/packages/client/lib/commands/ZUNION.ts b/packages/client/lib/commands/ZUNION.ts
index 09614b9dc01..8ee7196248f 100644
--- a/packages/client/lib/commands/ZUNION.ts
+++ b/packages/client/lib/commands/ZUNION.ts
@@ -1,5 +1,6 @@
 import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
-import { ZKeys, pushZKeysArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { ZKeys, parseZKeysArguments } from './generic-transformers';
 
 export interface ZUnionOptions {
   AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
@@ -8,17 +9,14 @@ export interface ZUnionOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: true,
-  transformArguments(
-    keys: ZKeys,
-    options?: ZUnionOptions
-  ) {
-    const args = pushZKeysArguments(['ZUNION'], keys);
+  parseCommand(parser: CommandParser, keys: ZKeys, options?: ZUnionOptions) {
+    parser.push('ZUNION');
+    parseZKeysArguments(parser, keys);
 
     if (options?.AGGREGATE) {
-      args.push('AGGREGATE', options.AGGREGATE);
+      parser.pushVariadic(['AGGREGATE', options.AGGREGATE]);
     }
-
-    return args;
   },
+  transformArguments(keys: ZKeys, options?: ZUnionOptions) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZUNIONSTORE.spec.ts b/packages/client/lib/commands/ZUNIONSTORE.spec.ts
index 7a01e80f0c0..a369a649311 100644
--- a/packages/client/lib/commands/ZUNIONSTORE.spec.ts
+++ b/packages/client/lib/commands/ZUNIONSTORE.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZUNIONSTORE from './ZUNIONSTORE';
+import { parseArgs } from './generic-transformers';
 
 describe('ZUNIONSTORE', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZUNIONSTORE.transformArguments('destination', 'source'),
+        parseArgs(ZUNIONSTORE, 'destination', 'source'),
         ['ZUNIONSTORE', 'destination', '1', 'source']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZUNIONSTORE.transformArguments('destination', ['1', '2']),
+        parseArgs(ZUNIONSTORE, 'destination', ['1', '2']),
         ['ZUNIONSTORE', 'destination', '2', '1', '2']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZUNIONSTORE.transformArguments('destination', {
+        parseArgs(ZUNIONSTORE, 'destination', {
           key: 'source',
           weight: 1
         }),
@@ -30,7 +31,7 @@ describe('ZUNIONSTORE', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZUNIONSTORE.transformArguments('destination', [{
+        parseArgs(ZUNIONSTORE, 'destination', [{
           key: 'a',
           weight: 1
         }, {
@@ -43,7 +44,7 @@ describe('ZUNIONSTORE', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZUNIONSTORE.transformArguments('destination', 'source', {
+        parseArgs(ZUNIONSTORE, 'destination', 'source', {
           AGGREGATE: 'SUM'
         }),
         ['ZUNIONSTORE', 'destination', '1', 'source', 'AGGREGATE', 'SUM']
diff --git a/packages/client/lib/commands/ZUNIONSTORE.ts b/packages/client/lib/commands/ZUNIONSTORE.ts
index a14d3ba31c9..d4237ad471c 100644
--- a/packages/client/lib/commands/ZUNIONSTORE.ts
+++ b/packages/client/lib/commands/ZUNIONSTORE.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NumberReply, Command, } from '../RESP/types';
-import { ZKeys, pushZKeysArguments } from './generic-transformers';
+import { CommandParser } from '../client/parser';
+import { ZKeys, parseZKeysArguments } from './generic-transformers';
 
 export interface ZUnionOptions {
   AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
@@ -8,18 +9,20 @@ export interface ZUnionOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     destination: RedisArgument,
     keys: ZKeys,
     options?: ZUnionOptions
-  ) {
-    const args = pushZKeysArguments(['ZUNIONSTORE', destination], keys);
-
+  ): any {
+    parser.push('ZUNIONSTORE');
+    parser.pushKey(destination);
+    parseZKeysArguments(parser, keys);
+    
     if (options?.AGGREGATE) {
-      args.push('AGGREGATE', options.AGGREGATE);
+      parser.pushVariadic(['AGGREGATE', options.AGGREGATE]);
     }
-
-    return args;
   },
+  transformArguments(destination: RedisArgument, keys: ZKeys, options?: ZUnionOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts b/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts
index bbf3ec676e8..dee735fc99f 100644
--- a/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts
+++ b/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts
@@ -1,6 +1,7 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ZUNION_WITHSCORES from './ZUNION_WITHSCORES';
+import { parseArgs } from './generic-transformers';
 
 describe('ZUNION WITHSCORES', () => {
   testUtils.isVersionGreaterThanHook([6, 2]);
@@ -8,21 +9,21 @@ describe('ZUNION WITHSCORES', () => {
   describe('transformArguments', () => {
     it('key (string)', () => {
       assert.deepEqual(
-        ZUNION_WITHSCORES.transformArguments('key'),
+        parseArgs(ZUNION_WITHSCORES, 'key'),
         ['ZUNION', '1', 'key', 'WITHSCORES']
       );
     });
 
     it('keys (Array<string>)', () => {
       assert.deepEqual(
-        ZUNION_WITHSCORES.transformArguments(['1', '2']),
+        parseArgs(ZUNION_WITHSCORES, ['1', '2']),
         ['ZUNION', '2', '1', '2', 'WITHSCORES']
       );
     });
 
     it('key & weight', () => {
       assert.deepEqual(
-        ZUNION_WITHSCORES.transformArguments({
+        parseArgs(ZUNION_WITHSCORES, {
           key: 'key',
           weight: 1
         }),
@@ -32,7 +33,7 @@ describe('ZUNION WITHSCORES', () => {
 
     it('keys & weights', () => {
       assert.deepEqual(
-        ZUNION_WITHSCORES.transformArguments([{
+        parseArgs(ZUNION_WITHSCORES, [{
           key: 'a',
           weight: 1
         }, {
@@ -45,7 +46,7 @@ describe('ZUNION WITHSCORES', () => {
 
     it('with AGGREGATE', () => {
       assert.deepEqual(
-        ZUNION_WITHSCORES.transformArguments('key', {
+        parseArgs(ZUNION_WITHSCORES, 'key', {
           AGGREGATE: 'SUM'
         }),
         ['ZUNION', '1', 'key', 'AGGREGATE', 'SUM', 'WITHSCORES']
diff --git a/packages/client/lib/commands/ZUNION_WITHSCORES.ts b/packages/client/lib/commands/ZUNION_WITHSCORES.ts
index d0895a3de76..87474f54a9c 100644
--- a/packages/client/lib/commands/ZUNION_WITHSCORES.ts
+++ b/packages/client/lib/commands/ZUNION_WITHSCORES.ts
@@ -1,14 +1,15 @@
 import { Command } from '../RESP/types';
+import { CommandParser } from '../client/parser';
 import ZUNION from './ZUNION';
-import { transformSortedSetReply } from './generic-transformers';
+import { Tail, transformSortedSetReply } from './generic-transformers';
 
 export default {
   FIRST_KEY_INDEX: ZUNION.FIRST_KEY_INDEX,
   IS_READ_ONLY: ZUNION.IS_READ_ONLY,
-  transformArguments(...args: Parameters<typeof ZUNION['transformArguments']>) {
-    const redisArgs = ZUNION.transformArguments(...args);
-    redisArgs.push('WITHSCORES');
-    return redisArgs;
+  parseCommand(parser: CommandParser, ...args: Tail<Parameters<typeof ZUNION.parseCommand>>) {
+    ZUNION.parseCommand(parser, ...args);
+    parser.push('WITHSCORES');
   },
+  transformArguments(...args: Parameters<typeof ZUNION['transformArguments']>) { return [] },
   transformReply: transformSortedSetReply
 } as const satisfies Command;
diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts
index d16e7b4cd32..c76d7a6216c 100644
--- a/packages/client/lib/commands/generic-transformers.ts
+++ b/packages/client/lib/commands/generic-transformers.ts
@@ -1,5 +1,5 @@
 import { UnwrapReply, ArrayReply, BlobStringReply, BooleanReply, CommandArguments, DoubleReply, NullReply, NumberReply, RedisArgument, TuplesReply, Command } from '../RESP/types';
-import { BasicCommandParser } from '../client/parser';
+import { BasicCommandParser, CommandParser } from '../client/parser';
 
 export function isNullReply(reply: unknown): reply is NullReply {
   return reply === null;
@@ -214,16 +214,16 @@ export function pushVariadicArgument(
   return args;
 }
 
-export function pushOptionalVariadicArgument(
-  args: CommandArguments,
+export function   parseOptionalVariadicArgument(
+  parser: CommandParser,
   name: RedisArgument,
   value?: RedisVariadicArgument
-): CommandArguments {
-  if (value === undefined) return args;
+) {
+  if (value === undefined) return;
 
-  args.push(name);
+  parser.push(name);
 
-  return pushVariadicArgument(args, value);
+  parser.pushVariadicWithLength(value);
 }
 
 export enum CommandFlags {
@@ -353,28 +353,28 @@ export interface SlotRange {
 }
 
 function pushSlotRangeArguments(
-  args: CommandArguments,
+  parser: CommandParser,
   range: SlotRange
 ): void {
-  args.push(
-    range.start.toString(),
-    range.end.toString()
+  parser.pushVariadic(
+    [
+      range.start.toString(),
+      range.end.toString()
+    ]
   );
 }
 
 export function pushSlotRangesArguments(
-  args: CommandArguments,
+  parser: CommandParser,
   ranges: SlotRange | Array<SlotRange>
-): CommandArguments {
+) {
   if (Array.isArray(ranges)) {
     for (const range of ranges) {
-      pushSlotRangeArguments(args, range);
+      pushSlotRangeArguments(parser, range);
     }
   } else {
-    pushSlotRangeArguments(args, ranges);
+    pushSlotRangeArguments(parser, ranges);
   }
-
-  return args;
 }
 
 export type RawRangeReply = [
@@ -403,41 +403,36 @@ export type ZVariadicKeys<T> = T | [T, ...Array<T>];
 
 export type ZKeys = ZVariadicKeys<RedisArgument> | ZVariadicKeys<ZKeyAndWeight>;
 
-export function pushZKeysArguments(
-  args: CommandArguments,
+export function parseZKeysArguments(
+  parser: CommandParser,
   keys: ZKeys
 ) {
   if (Array.isArray(keys)) {
-    args.push(keys.length.toString());
+    parser.push(keys.length.toString());
 
     if (keys.length) {
       if (isPlainKeys(keys)) {
-        args = args.concat(keys);
+        parser.pushKeys(keys);
       } else {
-        const start = args.length;
-        args[start + keys.length] = 'WEIGHTS';
         for (let i = 0; i < keys.length; i++) {
-          const index = start + i;
-          args[index] = keys[i].key;
-          args[index + 1 + keys.length] = transformDoubleArgument(keys[i].weight);
+          parser.pushKey(keys[i].key)
+        }
+        parser.push('WEIGHTS');
+        for (let i = 0; i < keys.length; i++) {
+          parser.push(transformDoubleArgument(keys[i].weight));
         }
       }
     }
   } else {
-    args.push('1');
+    parser.push('1');
 
     if (isPlainKey(keys)) {
-      args.push(keys);
+      parser.pushKey(keys);
     } else {
-      args.push(
-        keys.key,
-        'WEIGHTS',
-        transformDoubleArgument(keys.weight)
-      );
+      parser.pushKey(keys.key);
+      parser.pushVariadic(['WEIGHTS', transformDoubleArgument(keys.weight)]);
     }
   }
-
-  return args;
 }
 
 function isPlainKey(key: RedisArgument | ZKeyAndWeight): key is RedisArgument {
@@ -448,10 +443,12 @@ function isPlainKeys(keys: Array<RedisArgument> | Array<ZKeyAndWeight>): keys is
   return isPlainKey(keys[0]);
 }
 
+export type Tail<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? Tail : never;
+
 /**
  * @deprecated
  */
-export function parseArgs(command: Command, ...args: Array<any>) {
+export function parseArgs(command: Command, ...args: Array<any>): CommandArguments {
   if (command.parseCommand) {
     const parser = new BasicCommandParser();
     command.parseCommand!(parser, ...args);
@@ -465,12 +462,3 @@ export function parseArgs(command: Command, ...args: Array<any>) {
     return command.transformArguments(...args);
   }
 }
-
-/**
- * @deprecated
- */
-export function parseArgsWith(command: Command, ...args: Array<any>) {
-  const parser = new BasicCommandParser();
-  command.parseCommand!(parser, ...args);
-  return parser.preserve;
-}
diff --git a/packages/client/lib/test-utils.ts b/packages/client/lib/test-utils.ts
index 81aac6f9b03..a1702899adb 100644
--- a/packages/client/lib/test-utils.ts
+++ b/packages/client/lib/test-utils.ts
@@ -1,6 +1,8 @@
 import TestUtils from '@redis/test-utils';
 import { SinonSpy } from 'sinon';
 import { setTimeout } from 'node:timers/promises';
+import { Command } from './RESP/types';
+import { BasicCommandParser } from './client/parser';
 
 const utils = new TestUtils({
   dockerImageName: 'redis',
@@ -67,3 +69,9 @@ export const BLOCKING_MIN_VALUE = (
   utils.isVersionGreaterThan([6]) ? 0.01 :
   1
 );
+
+export function parseFirstKey(command: Command, ...args: Array<any>) {
+  const parser = new BasicCommandParser();
+  command.parseCommand!(parser, ...args);
+  return parser.firstKey;
+}
diff --git a/packages/graph/lib/commands/CONFIG_GET.spec.ts b/packages/graph/lib/commands/CONFIG_GET.spec.ts
index 42c7739f5d7..9a427867c63 100644
--- a/packages/graph/lib/commands/CONFIG_GET.spec.ts
+++ b/packages/graph/lib/commands/CONFIG_GET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CONFIG_GET from './CONFIG_GET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.CONFIG GET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CONFIG_GET.transformArguments('TIMEOUT'),
+      parseArgs(CONFIG_GET, 'TIMEOUT'),
       ['GRAPH.CONFIG', 'GET', 'TIMEOUT']
     );
   });
diff --git a/packages/graph/lib/commands/CONFIG_GET.ts b/packages/graph/lib/commands/CONFIG_GET.ts
index c7ed037e1a1..e953e450a86 100644
--- a/packages/graph/lib/commands/CONFIG_GET.ts
+++ b/packages/graph/lib/commands/CONFIG_GET.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, TuplesReply, ArrayReply, BlobStringReply, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 type ConfigItemReply = TuplesReply<[
   configKey: BlobStringReply,
@@ -8,8 +9,9 @@ type ConfigItemReply = TuplesReply<[
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments(configKey: RedisArgument) {
-    return ['GRAPH.CONFIG', 'GET', configKey];
+  parseCommand(parser: CommandParser, configKey: RedisArgument) {
+    parser.pushVariadic(['GRAPH.CONFIG', 'GET', configKey]);
   },
+  transformArguments(configKey: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ConfigItemReply | ArrayReply<ConfigItemReply>
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/CONFIG_SET.spec.ts b/packages/graph/lib/commands/CONFIG_SET.spec.ts
index 5ed51e78a29..ae6e296699c 100644
--- a/packages/graph/lib/commands/CONFIG_SET.spec.ts
+++ b/packages/graph/lib/commands/CONFIG_SET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CONFIG_SET from './CONFIG_SET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.CONFIG SET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      CONFIG_SET.transformArguments('TIMEOUT', 0),
+      parseArgs(CONFIG_SET, 'TIMEOUT', 0),
       ['GRAPH.CONFIG', 'SET', 'TIMEOUT', '0']
     );
   });
diff --git a/packages/graph/lib/commands/CONFIG_SET.ts b/packages/graph/lib/commands/CONFIG_SET.ts
index ba23ac2f1a7..f623cd3d11e 100644
--- a/packages/graph/lib/commands/CONFIG_SET.ts
+++ b/packages/graph/lib/commands/CONFIG_SET.ts
@@ -1,15 +1,12 @@
 import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: false,
-  transformArguments(configKey: RedisArgument, value: number) {
-    return [
-      'GRAPH.CONFIG',
-      'SET',
-      configKey,
-      value.toString()
-    ];
+  parseCommand(parser: CommandParser, configKey: RedisArgument, value: number) {
+    parser.pushVariadic(['GRAPH.CONFIG', 'SET', configKey, value.toString()]);
   },
+  transformArguments(configKey: RedisArgument, value: number) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/DELETE.spec.ts b/packages/graph/lib/commands/DELETE.spec.ts
index 6fe24fd827a..5977c646307 100644
--- a/packages/graph/lib/commands/DELETE.spec.ts
+++ b/packages/graph/lib/commands/DELETE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DELETE from './DELETE';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.DELETE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      DELETE.transformArguments('key'),
+      parseArgs(DELETE, 'key'),
       ['GRAPH.DELETE', 'key']
     );
   });
diff --git a/packages/graph/lib/commands/DELETE.ts b/packages/graph/lib/commands/DELETE.ts
index f5f99fb92cc..6342746aa95 100644
--- a/packages/graph/lib/commands/DELETE.ts
+++ b/packages/graph/lib/commands/DELETE.ts
@@ -1,10 +1,13 @@
 import { RedisArgument, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument) {
-    return ['GRAPH.DELETE', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('GRAPH.DELETE');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => BlobStringReply
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/EXPLAIN.spec.ts b/packages/graph/lib/commands/EXPLAIN.spec.ts
index 04bf838a4de..28f30cd17b3 100644
--- a/packages/graph/lib/commands/EXPLAIN.spec.ts
+++ b/packages/graph/lib/commands/EXPLAIN.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import EXPLAIN from './EXPLAIN';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.EXPLAIN', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      EXPLAIN.transformArguments('key', 'RETURN 0'),
+      parseArgs(EXPLAIN, 'key', 'RETURN 0'),
       ['GRAPH.EXPLAIN', 'key', 'RETURN 0']
     );
   });
diff --git a/packages/graph/lib/commands/EXPLAIN.ts b/packages/graph/lib/commands/EXPLAIN.ts
index 99a73bf04bf..557c1cf511c 100644
--- a/packages/graph/lib/commands/EXPLAIN.ts
+++ b/packages/graph/lib/commands/EXPLAIN.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, query: RedisArgument) {
-    return ['GRAPH.EXPLAIN', key, query];
+  parseCommand(parser: CommandParser, key: RedisArgument, query: RedisArgument) {
+    parser.push('GRAPH.EXPLAIN');
+    parser.pushKey(key);
+    parser.push(query);
   },
+  transformArguments(key: RedisArgument, query: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/LIST.spec.ts b/packages/graph/lib/commands/LIST.spec.ts
index 36745efc470..19f18a0e30b 100644
--- a/packages/graph/lib/commands/LIST.spec.ts
+++ b/packages/graph/lib/commands/LIST.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import LIST from './LIST';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.LIST', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      LIST.transformArguments(),
+      parseArgs(LIST),
       ['GRAPH.LIST']
     );
   });
diff --git a/packages/graph/lib/commands/LIST.ts b/packages/graph/lib/commands/LIST.ts
index 01a868854be..6d57640ef71 100644
--- a/packages/graph/lib/commands/LIST.ts
+++ b/packages/graph/lib/commands/LIST.ts
@@ -1,10 +1,12 @@
 import { ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: undefined,
   IS_READ_ONLY: true,
-  transformArguments() {
-    return ['GRAPH.LIST'];
+  parseCommand(parser: CommandParser) {
+    parser.push('GRAPH.LIST');
   },
+  transformArguments() { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/PROFILE.spec.ts b/packages/graph/lib/commands/PROFILE.spec.ts
index a758365d56e..7f16fd3ba58 100644
--- a/packages/graph/lib/commands/PROFILE.spec.ts
+++ b/packages/graph/lib/commands/PROFILE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import PROFILE from './PROFILE';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.PROFILE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      PROFILE.transformArguments('key', 'RETURN 0'),
+      parseArgs(PROFILE, 'key', 'RETURN 0'),
       ['GRAPH.PROFILE', 'key', 'RETURN 0']
     );
   });
diff --git a/packages/graph/lib/commands/PROFILE.ts b/packages/graph/lib/commands/PROFILE.ts
index 2aa1e83dfb0..1dd56647a8e 100644
--- a/packages/graph/lib/commands/PROFILE.ts
+++ b/packages/graph/lib/commands/PROFILE.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, query: RedisArgument) {
-    return ['GRAPH.PROFILE', key, query];
+  parseCommand(parser: CommandParser, key: RedisArgument, query: RedisArgument) {
+    parser.push('GRAPH.PROFILE');
+    parser.pushKey(key);
+    parser.push(query);
   },
+  transformArguments(key: RedisArgument, query: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/QUERY.spec.ts b/packages/graph/lib/commands/QUERY.spec.ts
index fef9ccad478..38caa5ff9e1 100644
--- a/packages/graph/lib/commands/QUERY.spec.ts
+++ b/packages/graph/lib/commands/QUERY.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import QUERY from './QUERY';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.QUERY', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        QUERY.transformArguments('key', 'query'),
+        parseArgs(QUERY, 'key', 'query'),
         ['GRAPH.QUERY', 'key', 'query']
       );
     });
@@ -14,7 +15,7 @@ describe('GRAPH.QUERY', () => {
     describe('params', () => {
       it('all types', () => {
         assert.deepEqual(
-          QUERY.transformArguments('key', 'query', {
+          parseArgs(QUERY, 'key', 'query', {
             params: {
               null: null,
               string: '"\\',
@@ -30,7 +31,7 @@ describe('GRAPH.QUERY', () => {
   
       it('TypeError', () => {
         assert.throws(() => {
-          QUERY.transformArguments('key', 'query', {
+          parseArgs(QUERY, 'key', 'query', {
             params: {
               a: Buffer.from('a')
             }
@@ -41,7 +42,7 @@ describe('GRAPH.QUERY', () => {
   
     it('TIMEOUT', () => {
       assert.deepEqual(
-        QUERY.transformArguments('key', 'query', {
+        parseArgs(QUERY, 'key', 'query', {
           TIMEOUT: 1
         }),
         ['GRAPH.QUERY', 'key', 'query', 'TIMEOUT', '1']
@@ -50,7 +51,7 @@ describe('GRAPH.QUERY', () => {
   
     it('compact', () => {
       assert.deepEqual(
-        QUERY.transformArguments('key', 'query', undefined, true),
+        parseArgs(QUERY, 'key', 'query', undefined, true),
         ['GRAPH.QUERY', 'key', 'query', '--compact']
       );
     });
diff --git a/packages/graph/lib/commands/QUERY.ts b/packages/graph/lib/commands/QUERY.ts
index 8a052354610..125b4a968a8 100644
--- a/packages/graph/lib/commands/QUERY.ts
+++ b/packages/graph/lib/commands/QUERY.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, NumberReply, NullReply, TuplesReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 type Headers = ArrayReply<BlobStringReply>;
 
@@ -25,30 +26,28 @@ export interface QueryOptions {
   TIMEOUT?: number;
 }
 
-export function transformQueryArguments(
+export function parseQueryArguments(
   command: RedisArgument,
+  parser: CommandParser,
   graph: RedisArgument,
   query: RedisArgument,
   options?: QueryOptions,
   compact?: boolean
 ) {
-  const args = [
-    command,
-    graph,
-    options?.params ?
-      `CYPHER ${queryParamsToString(options.params)} ${query}` :
-      query
-  ];
+  parser.push(command);
+  parser.pushKey(graph);
+  const param = options?.params ?
+    `CYPHER ${queryParamsToString(options.params)} ${query}` :
+    query;
+  parser.push(param);
 
   if (options?.TIMEOUT !== undefined) {
-    args.push('TIMEOUT', options.TIMEOUT.toString());
+    parser.pushVariadic(['TIMEOUT', options.TIMEOUT.toString()]);
   }
 
   if (compact) {
-    args.push('--compact');
+    parser.push('--compact');
   }
-
-  return args;
 }
 
 function queryParamsToString(params: QueryParams) {
@@ -87,7 +86,8 @@ function queryParamToString(param: QueryParam): string {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments: transformQueryArguments.bind(undefined, 'GRAPH.QUERY'),
+  parseCommand: parseQueryArguments.bind(undefined, 'GRAPH.QUERY'),
+  transformArguments(graph: RedisArgument, query: RedisArgument, options?: QueryOptions, compact?: boolean) { return [] },
   transformReply(reply: UnwrapReply<QueryRawReply>) {
     return reply.length === 1 ? {
       headers: undefined,
diff --git a/packages/graph/lib/commands/RO_QUERY.spec.ts b/packages/graph/lib/commands/RO_QUERY.spec.ts
index 13829543552..fa9459cf642 100644
--- a/packages/graph/lib/commands/RO_QUERY.spec.ts
+++ b/packages/graph/lib/commands/RO_QUERY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import RO_QUERY from './RO_QUERY';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.RO_QUERY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      RO_QUERY.transformArguments('key', 'query'),
+      parseArgs(RO_QUERY, 'key', 'query'),
       ['GRAPH.RO_QUERY', 'key', 'query']
     );
   });
diff --git a/packages/graph/lib/commands/RO_QUERY.ts b/packages/graph/lib/commands/RO_QUERY.ts
index 5987f511b7d..9fea6c9703f 100644
--- a/packages/graph/lib/commands/RO_QUERY.ts
+++ b/packages/graph/lib/commands/RO_QUERY.ts
@@ -1,9 +1,10 @@
 import { Command } from '@redis/client/dist/lib/RESP/types';
-import QUERY, { transformQueryArguments } from './QUERY';
+import QUERY, { parseQueryArguments } from './QUERY';
 
 export default {
   FIRST_KEY_INDEX: QUERY.FIRST_KEY_INDEX,
   IS_READ_ONLY: true,
-  transformArguments: transformQueryArguments.bind(undefined, 'GRAPH.RO_QUERY'),
+  parseCommand: parseQueryArguments.bind(undefined, 'GRAPH.RO_QUERY'),
+  transformArguments: QUERY.transformArguments,
   transformReply: QUERY.transformReply
 } as const satisfies Command;
diff --git a/packages/graph/lib/commands/SLOWLOG.spec.ts b/packages/graph/lib/commands/SLOWLOG.spec.ts
index c1c77286a26..b991d6e7b96 100644
--- a/packages/graph/lib/commands/SLOWLOG.spec.ts
+++ b/packages/graph/lib/commands/SLOWLOG.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SLOWLOG from './SLOWLOG';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('GRAPH.SLOWLOG', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      SLOWLOG.transformArguments('key'),
+      parseArgs(SLOWLOG, 'key'),
       ['GRAPH.SLOWLOG', 'key']
     );
   });
diff --git a/packages/graph/lib/commands/SLOWLOG.ts b/packages/graph/lib/commands/SLOWLOG.ts
index 52927f6040b..12bdde36fc9 100644
--- a/packages/graph/lib/commands/SLOWLOG.ts
+++ b/packages/graph/lib/commands/SLOWLOG.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 type SlowLogRawReply = ArrayReply<TuplesReply<[
   timestamp: BlobStringReply,
@@ -10,9 +11,11 @@ type SlowLogRawReply = ArrayReply<TuplesReply<[
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument) {
-    return ['GRAPH.SLOWLOG', key];
+  parseCommand(parser: CommandParser, key: RedisArgument) {
+    parser.push('GRAPH.SLOWLOG');
+    parser.pushKey(key);
   },
+  transformArguments(key: RedisArgument) { return [] },
   transformReply(reply: UnwrapReply<SlowLogRawReply>) {
     return reply.map(log => {
       const [timestamp, command, query, took] = log as unknown as UnwrapReply<typeof log>;
diff --git a/packages/json/lib/commands/ARRAPPEND.spec.ts b/packages/json/lib/commands/ARRAPPEND.spec.ts
index 3bdd967e237..b2c22e0b9c0 100644
--- a/packages/json/lib/commands/ARRAPPEND.spec.ts
+++ b/packages/json/lib/commands/ARRAPPEND.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRAPPEND from './ARRAPPEND';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRAPPEND', () => {
   describe('transformArguments', () => {
     it('single element', () => {
       assert.deepEqual(
-        ARRAPPEND.transformArguments('key', '$', 'value'),
+        parseArgs(ARRAPPEND, 'key', '$', 'value'),
         ['JSON.ARRAPPEND', 'key', '$', '"value"']
       );
     });
 
     it('multiple elements', () => {
       assert.deepEqual(
-        ARRAPPEND.transformArguments('key', '$', 1, 2),
+        parseArgs(ARRAPPEND, 'key', '$', 1, 2),
         ['JSON.ARRAPPEND', 'key', '$', '1', '2']
       );
     });
diff --git a/packages/json/lib/commands/ARRAPPEND.ts b/packages/json/lib/commands/ARRAPPEND.ts
index 6f486a301d7..bdee1410937 100644
--- a/packages/json/lib/commands/ARRAPPEND.ts
+++ b/packages/json/lib/commands/ARRAPPEND.ts
@@ -1,27 +1,25 @@
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 import { RedisJSON, transformRedisJsonArgument } from '.';
 import { RedisArgument, NumberReply, ArrayReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     path: RedisArgument,
     json: RedisJSON,
     ...jsons: Array<RedisJSON>
   ) {
-    const args = new Array<RedisArgument>(4 + jsons.length);
-    args[0] = 'JSON.ARRAPPEND';
-    args[1] = key;
-    args[2] = path;
-    args[3] = transformRedisJsonArgument(json);
+    parser.push('JSON.ARRAPPEND');
+    parser.pushKey(key);
+    parser.pushVariadic([path, transformRedisJsonArgument(json)]);
 
-    let argsIndex = 4;
     for (let i = 0; i < jsons.length; i++) {
-      args[argsIndex++] = transformRedisJsonArgument(jsons[i]);
+      parser.push(transformRedisJsonArgument(jsons[i]));
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, json: RedisJSON, ...jsons: Array<RedisJSON>) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/ARRINDEX.spec.ts b/packages/json/lib/commands/ARRINDEX.spec.ts
index cb946b62515..3c1377354f1 100644
--- a/packages/json/lib/commands/ARRINDEX.spec.ts
+++ b/packages/json/lib/commands/ARRINDEX.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRINDEX from './ARRINDEX';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRINDEX', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ARRINDEX.transformArguments('key', '$', 'value'),
+        parseArgs(ARRINDEX, 'key', '$', 'value'),
         ['JSON.ARRINDEX', 'key', '$', '"value"']
       );
     });
@@ -14,7 +15,7 @@ describe('JSON.ARRINDEX', () => {
     describe('with range', () => {
       it('start only', () => {
         assert.deepEqual(
-          ARRINDEX.transformArguments('key', '$', 'value', {
+          parseArgs(ARRINDEX, 'key', '$', 'value', {
             range: {
               start: 0
             }
@@ -25,7 +26,7 @@ describe('JSON.ARRINDEX', () => {
 
       it('with start and stop', () => {
         assert.deepEqual(
-          ARRINDEX.transformArguments('key', '$', 'value', {
+          parseArgs(ARRINDEX, 'key', '$', 'value', {
             range: {
               start: 0,
               stop: 1
diff --git a/packages/json/lib/commands/ARRINDEX.ts b/packages/json/lib/commands/ARRINDEX.ts
index 77c54b92522..f5fd4a41599 100644
--- a/packages/json/lib/commands/ARRINDEX.ts
+++ b/packages/json/lib/commands/ARRINDEX.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, NumberReply, ArrayReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
 import { RedisJSON, transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonArrIndexOptions {
   range?: {
@@ -11,23 +12,30 @@ export interface JsonArrIndexOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     path: RedisArgument,
     json: RedisJSON,
     options?: JsonArrIndexOptions
   ) {
-    const args = ['JSON.ARRINDEX', key, path, transformRedisJsonArgument(json)];
+    parser.push('JSON.ARRINDEX');
+    parser.pushKey(key);
+    parser.pushVariadic([path, transformRedisJsonArgument(json)]);
 
     if (options?.range) {
-      args.push(options.range.start.toString());
+      parser.push(options.range.start.toString());
 
       if (options.range.stop !== undefined) {
-        args.push(options.range.stop.toString());
+        parser.push(options.range.stop.toString());
       }
     }
-
-    return args;
   },
+  transformArguments(
+    key: RedisArgument,
+    path: RedisArgument,
+    json: RedisJSON,
+    options?: JsonArrIndexOptions
+  ) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/ARRINSERT.spec.ts b/packages/json/lib/commands/ARRINSERT.spec.ts
index efa824b3738..bf9c8a2a051 100644
--- a/packages/json/lib/commands/ARRINSERT.spec.ts
+++ b/packages/json/lib/commands/ARRINSERT.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRINSERT from './ARRINSERT';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRINSERT', () => {
   describe('transformArguments', () => {
     it('single element', () => {
       assert.deepEqual(
-        ARRINSERT.transformArguments('key', '$', 0, 'value'),
+        parseArgs(ARRINSERT, 'key', '$', 0, 'value'),
         ['JSON.ARRINSERT', 'key', '$', '0', '"value"']
       );
     });
 
     it('multiple elements', () => {
       assert.deepEqual(
-        ARRINSERT.transformArguments('key', '$', 0, '1', '2'),
+        parseArgs(ARRINSERT, 'key', '$', 0, '1', '2'),
         ['JSON.ARRINSERT', 'key', '$', '0', '"1"', '"2"']
       );
     });
diff --git a/packages/json/lib/commands/ARRINSERT.ts b/packages/json/lib/commands/ARRINSERT.ts
index c0891884725..5ea746dcf29 100644
--- a/packages/json/lib/commands/ARRINSERT.ts
+++ b/packages/json/lib/commands/ARRINSERT.ts
@@ -1,29 +1,26 @@
 import { RedisArgument, NumberReply, ArrayReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
 import { RedisJSON, transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     path: RedisArgument,
     index: number,
     json: RedisJSON,
     ...jsons: Array<RedisJSON>
   ) {
-    const args = new Array<RedisArgument>(4 + jsons.length);
-    args[0] = 'JSON.ARRINSERT';
-    args[1] = key;
-    args[2] = path;
-    args[3] = index.toString();
-    args[4] = transformRedisJsonArgument(json);
+    parser.push('JSON.ARRINSERT');
+    parser.pushKey(key);
+    parser.pushVariadic([path, index.toString(), transformRedisJsonArgument(json)]);
 
-    let argsIndex = 5;
     for (let i = 0; i < jsons.length; i++) {
-      args[argsIndex++] = transformRedisJsonArgument(jsons[i]);
+      parser.push(transformRedisJsonArgument(jsons[i]));
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, index: number, json: RedisJSON,...jsons: Array<RedisJSON>) {return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/ARRLEN.spec.ts b/packages/json/lib/commands/ARRLEN.spec.ts
index 5ecb01b2ce5..dcf7d35acb0 100644
--- a/packages/json/lib/commands/ARRLEN.spec.ts
+++ b/packages/json/lib/commands/ARRLEN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRLEN from './ARRLEN';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRLEN', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ARRLEN.transformArguments('key'),
+        parseArgs(ARRLEN, 'key'),
         ['JSON.ARRLEN', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        ARRLEN.transformArguments('key', {
+        parseArgs(ARRLEN, 'key', {
           path: '$'
         }),
         ['JSON.ARRLEN', 'key', '$']
diff --git a/packages/json/lib/commands/ARRLEN.ts b/packages/json/lib/commands/ARRLEN.ts
index d30032c7d86..54fd54b8d9d 100644
--- a/packages/json/lib/commands/ARRLEN.ts
+++ b/packages/json/lib/commands/ARRLEN.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, NumberReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonArrLenOptions {
   path?: RedisArgument;
@@ -7,14 +8,13 @@ export interface JsonArrLenOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options?: JsonArrLenOptions) {
-    const args = ['JSON.ARRLEN', key];
-
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonArrLenOptions) {
+    parser.push('JSON.ARRLEN');
+    parser.pushKey(key);
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonArrLenOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/ARRPOP.spec.ts b/packages/json/lib/commands/ARRPOP.spec.ts
index 1b069ba3928..f823e7fc08a 100644
--- a/packages/json/lib/commands/ARRPOP.spec.ts
+++ b/packages/json/lib/commands/ARRPOP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRPOP from './ARRPOP';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRPOP', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        ARRPOP.transformArguments('key'),
+        parseArgs(ARRPOP, 'key'),
         ['JSON.ARRPOP', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        ARRPOP.transformArguments('key', {
+        parseArgs(ARRPOP, 'key', {
           path: '$'
         }),
         ['JSON.ARRPOP', 'key', '$']
@@ -22,7 +23,7 @@ describe('JSON.ARRPOP', () => {
 
     it('with path and index', () => {
       assert.deepEqual(
-        ARRPOP.transformArguments('key', {
+        parseArgs(ARRPOP, 'key', {
           path: '$',
           index: 0
         }),
diff --git a/packages/json/lib/commands/ARRPOP.ts b/packages/json/lib/commands/ARRPOP.ts
index 4eafe9fdde4..101fd4c18d8 100644
--- a/packages/json/lib/commands/ARRPOP.ts
+++ b/packages/json/lib/commands/ARRPOP.ts
@@ -1,6 +1,7 @@
 import { RedisArgument, ArrayReply, NullReply, BlobStringReply, Command, UnwrapReply } from '@redis/client/dist/lib/RESP/types';
 import { isArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
 import { transformRedisJsonNullReply } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface RedisArrPopOptions {
   path: RedisArgument;
@@ -10,19 +11,19 @@ export interface RedisArrPopOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: RedisArrPopOptions) {
-    const args = ['JSON.ARRPOP', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: RedisArrPopOptions) {
+    parser.push('JSON.ARRPOP');
+    parser.pushKey(key);
 
     if (options) {
-      args.push(options.path);
+      parser.push(options.path);
 
       if (options.index !== undefined) {
-        args.push(options.index.toString());
+        parser.push(options.index.toString());
       }
     }
-    
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: RedisArrPopOptions) { return [] },
   transformReply(reply: NullReply | BlobStringReply | ArrayReply<NullReply | BlobStringReply>) {
     return isArrayReply(reply) ?
       (reply as unknown as UnwrapReply<typeof reply>).map(item => transformRedisJsonNullReply(item)) :
diff --git a/packages/json/lib/commands/ARRTRIM.spec.ts b/packages/json/lib/commands/ARRTRIM.spec.ts
index 4c2f72aaa50..e346716e8df 100644
--- a/packages/json/lib/commands/ARRTRIM.spec.ts
+++ b/packages/json/lib/commands/ARRTRIM.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import ARRTRIM from './ARRTRIM';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.ARRTRIM', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      ARRTRIM.transformArguments('key', '$', 0, 1),
+      parseArgs(ARRTRIM, 'key', '$', 0, 1),
       ['JSON.ARRTRIM', 'key', '$', '0', '1']
     );
   });
diff --git a/packages/json/lib/commands/ARRTRIM.ts b/packages/json/lib/commands/ARRTRIM.ts
index ab31f159491..8896730ffce 100644
--- a/packages/json/lib/commands/ARRTRIM.ts
+++ b/packages/json/lib/commands/ARRTRIM.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, NumberReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, path: RedisArgument, start: number, stop: number) {
-    return ['JSON.ARRTRIM', key, path, start.toString(), stop.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, path: RedisArgument, start: number, stop: number) {
+    parser.push('JSON.ARRTRIM');
+    parser.pushKey(key);
+    parser.pushVariadic([path, start.toString(), stop.toString()]);
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, start: number, stop: number) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/CLEAR.spec.ts b/packages/json/lib/commands/CLEAR.spec.ts
index 983e6bec2d9..c1786cc1dde 100644
--- a/packages/json/lib/commands/CLEAR.spec.ts
+++ b/packages/json/lib/commands/CLEAR.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import CLEAR from './CLEAR';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.CLEAR', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        CLEAR.transformArguments('key'),
+        parseArgs(CLEAR, 'key'),
         ['JSON.CLEAR', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        CLEAR.transformArguments('key', {
+        parseArgs(CLEAR, 'key', {
           path: '$'
         }),
         ['JSON.CLEAR', 'key', '$']
diff --git a/packages/json/lib/commands/CLEAR.ts b/packages/json/lib/commands/CLEAR.ts
index 23e86d900e7..fad89e6bca9 100644
--- a/packages/json/lib/commands/CLEAR.ts
+++ b/packages/json/lib/commands/CLEAR.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonClearOptions {
   path?: RedisArgument;
@@ -7,14 +8,14 @@ export interface JsonClearOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonClearOptions) {
-    const args = ['JSON.CLEAR', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonClearOptions) {
+    parser.push('JSON.CLEAR');
+    parser.pushKey(key);
 
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonClearOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/DEBUG_MEMORY.spec.ts b/packages/json/lib/commands/DEBUG_MEMORY.spec.ts
index c41d07cb27e..09c29328d8e 100644
--- a/packages/json/lib/commands/DEBUG_MEMORY.spec.ts
+++ b/packages/json/lib/commands/DEBUG_MEMORY.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DEBUG_MEMORY from './DEBUG_MEMORY';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.DEBUG MEMORY', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        DEBUG_MEMORY.transformArguments('key'),
+        parseArgs(DEBUG_MEMORY, 'key'),
         ['JSON.DEBUG', 'MEMORY', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        DEBUG_MEMORY.transformArguments('key', {
+        parseArgs(DEBUG_MEMORY, 'key', {
           path: '$'
         }),
         ['JSON.DEBUG', 'MEMORY', 'key', '$']
diff --git a/packages/json/lib/commands/DEBUG_MEMORY.ts b/packages/json/lib/commands/DEBUG_MEMORY.ts
index c2e730b9dc2..9dfe6552f77 100644
--- a/packages/json/lib/commands/DEBUG_MEMORY.ts
+++ b/packages/json/lib/commands/DEBUG_MEMORY.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonDebugMemoryOptions {
   path?: RedisArgument;
@@ -7,14 +8,14 @@ export interface JsonDebugMemoryOptions {
 export default {
   FIRST_KEY_INDEX: 2,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonDebugMemoryOptions) {
-    const args = ['JSON.DEBUG', 'MEMORY', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonDebugMemoryOptions) {
+    parser.pushVariadic(['JSON.DEBUG', 'MEMORY']);
+    parser.pushKey(key);
 
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonDebugMemoryOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/DEL.spec.ts b/packages/json/lib/commands/DEL.spec.ts
index 18f6a8f2db6..a008c3b9b2b 100644
--- a/packages/json/lib/commands/DEL.spec.ts
+++ b/packages/json/lib/commands/DEL.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import DEL from './DEL';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.DEL', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        DEL.transformArguments('key'),
+        parseArgs(DEL, 'key'),
         ['JSON.DEL', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        DEL.transformArguments('key', {
+        parseArgs(DEL, 'key', {
           path: '$.path'
         }),
         ['JSON.DEL', 'key', '$.path']
diff --git a/packages/json/lib/commands/DEL.ts b/packages/json/lib/commands/DEL.ts
index f6952a8dc63..a66aa205584 100644
--- a/packages/json/lib/commands/DEL.ts
+++ b/packages/json/lib/commands/DEL.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonDelOptions {
   path?: RedisArgument
@@ -7,14 +8,14 @@ export interface JsonDelOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonDelOptions) {
-    const args = ['JSON.DEL', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonDelOptions) {
+    parser.push('JSON.DEL');
+    parser.pushKey(key);
 
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonDelOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/FORGET.spec.ts b/packages/json/lib/commands/FORGET.spec.ts
index 04066ec43a9..888fff5659b 100644
--- a/packages/json/lib/commands/FORGET.spec.ts
+++ b/packages/json/lib/commands/FORGET.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import FORGET from './FORGET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.FORGET', () => {
   describe('transformArguments', () => {
     it('key', () => {
       assert.deepEqual(
-        FORGET.transformArguments('key'),
+        parseArgs(FORGET, 'key'),
         ['JSON.FORGET', 'key']
       );
     });
 
     it('key, path', () => {
       assert.deepEqual(
-        FORGET.transformArguments('key', {
+        parseArgs(FORGET, 'key', {
           path: '$.path'
         }),
         ['JSON.FORGET', 'key', '$.path']
diff --git a/packages/json/lib/commands/FORGET.ts b/packages/json/lib/commands/FORGET.ts
index 68335ee92e9..6042ad3514b 100644
--- a/packages/json/lib/commands/FORGET.ts
+++ b/packages/json/lib/commands/FORGET.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonForgetOptions {
   path?: RedisArgument;
@@ -7,14 +8,14 @@ export interface JsonForgetOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonForgetOptions) {
-    const args = ['JSON.FORGET', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonForgetOptions) {
+    parser.push('JSON.FORGET');
+    parser.pushKey(key);
 
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonForgetOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/GET.spec.ts b/packages/json/lib/commands/GET.spec.ts
index 6d6ff14f67f..0741de316e1 100644
--- a/packages/json/lib/commands/GET.spec.ts
+++ b/packages/json/lib/commands/GET.spec.ts
@@ -1,12 +1,13 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import GET from './GET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.GET', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        GET.transformArguments('key'),
+        parseArgs(GET, 'key'),
         ['JSON.GET', 'key']
       );
     });
@@ -14,14 +15,14 @@ describe('JSON.GET', () => {
     describe('with path', () => {
       it('string', () => {
         assert.deepEqual(
-          GET.transformArguments('key', { path: '$' }),
+          parseArgs(GET, 'key', { path: '$' }),
           ['JSON.GET', 'key', '$']
         );
       });
 
       it('array', () => {
         assert.deepEqual(
-          GET.transformArguments('key', { path: ['$.1', '$.2'] }),
+          parseArgs(GET, 'key', { path: ['$.1', '$.2'] }),
           ['JSON.GET', 'key', '$.1', '$.2']
         );
       });
diff --git a/packages/json/lib/commands/GET.ts b/packages/json/lib/commands/GET.ts
index b7bcc52e3cb..ce1b8282fea 100644
--- a/packages/json/lib/commands/GET.ts
+++ b/packages/json/lib/commands/GET.ts
@@ -1,6 +1,7 @@
 import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
-import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
+import { RedisVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers';
 import { transformRedisJsonNullReply } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonGetOptions {
   path?: RedisVariadicArgument;
@@ -9,14 +10,13 @@ export interface JsonGetOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonGetOptions) {
-    let args = ['JSON.GET', key];
-
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonGetOptions) {
+    parser.push('JSON.GET');
+    parser.pushKey(key);
     if (options?.path !== undefined) {
-      args = pushVariadicArguments(args, options.path);
+      parser.pushVariadic(options.path)
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonGetOptions) { return [] },
   transformReply: transformRedisJsonNullReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/MERGE.spec.ts b/packages/json/lib/commands/MERGE.spec.ts
index 56f5d25e7d5..30a092035c5 100644
--- a/packages/json/lib/commands/MERGE.spec.ts
+++ b/packages/json/lib/commands/MERGE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MERGE from './MERGE';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.MERGE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MERGE.transformArguments('key', '$', 'value'),
+      parseArgs(MERGE, 'key', '$', 'value'),
       ['JSON.MERGE', 'key', '$', '"value"']
     );
   });
diff --git a/packages/json/lib/commands/MERGE.ts b/packages/json/lib/commands/MERGE.ts
index 90cd080a06e..c65749b2feb 100644
--- a/packages/json/lib/commands/MERGE.ts
+++ b/packages/json/lib/commands/MERGE.ts
@@ -1,16 +1,15 @@
 import { SimpleStringReply, Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
 import { RedisJSON, transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, path: RedisArgument, value: RedisJSON) {
-    return [
-      'JSON.MERGE',
-      key,
-      path,
-      transformRedisJsonArgument(value)
-    ];
+  parseCommand(parser: CommandParser, key: RedisArgument, path: RedisArgument, value: RedisJSON) {
+    parser.push('JSON.MERGE');
+    parser.pushKey(key);
+    parser.pushVariadic([path, transformRedisJsonArgument(value)]);
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, value: RedisJSON) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/MGET.spec.ts b/packages/json/lib/commands/MGET.spec.ts
index 1bfaecd6da9..2d8efafde71 100644
--- a/packages/json/lib/commands/MGET.spec.ts
+++ b/packages/json/lib/commands/MGET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MGET from './MGET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.MGET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MGET.transformArguments(['1', '2'], '$'),
+      parseArgs(MGET, ['1', '2'], '$'),
       ['JSON.MGET', '1', '2', '$']
     );
   });
diff --git a/packages/json/lib/commands/MGET.ts b/packages/json/lib/commands/MGET.ts
index a7aea82ac2e..f0c8a0aacb4 100644
--- a/packages/json/lib/commands/MGET.ts
+++ b/packages/json/lib/commands/MGET.ts
@@ -1,16 +1,16 @@
 import { RedisArgument, UnwrapReply, ArrayReply, NullReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
 import { transformRedisJsonNullReply } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(keys: Array<RedisArgument>, path: RedisArgument) {
-    return [
-      'JSON.MGET',
-      ...keys,
-      path
-    ];
+  parseCommand(parser: CommandParser, keys: Array<RedisArgument>, path: RedisArgument) {
+    parser.push('JSON.MGET');
+    parser.pushKeys(keys);
+    parser.push(path);
   },
+  transformArguments(keys: Array<RedisArgument>, path: RedisArgument) { return [] },
   transformReply(reply: UnwrapReply<ArrayReply<NullReply | BlobStringReply>>) {
     return reply.map(json => transformRedisJsonNullReply(json))
   }
diff --git a/packages/json/lib/commands/MSET.spec.ts b/packages/json/lib/commands/MSET.spec.ts
index 360890234c8..38e8b077e81 100644
--- a/packages/json/lib/commands/MSET.spec.ts
+++ b/packages/json/lib/commands/MSET.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import MSET from './MSET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.MSET', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      MSET.transformArguments([{
+      parseArgs(MSET, [{
         key: '1',
         path: '$',
         value: 1
diff --git a/packages/json/lib/commands/MSET.ts b/packages/json/lib/commands/MSET.ts
index a081bfd543a..3f52e872373 100644
--- a/packages/json/lib/commands/MSET.ts
+++ b/packages/json/lib/commands/MSET.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
 import { RedisJSON, transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonMSetItem {
   key: RedisArgument;
@@ -10,19 +11,14 @@ export interface JsonMSetItem {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(items: Array<JsonMSetItem>) {
-    const args = new Array<RedisArgument>(1 + items.length * 3);
-    args[0] = 'JSON.MSET';
+  parseCommand(parser: CommandParser, items: Array<JsonMSetItem>) {
+    parser.push('JSON.MSET');
 
-    let argsIndex = 1;
     for (let i = 0; i < items.length; i++) {
-      const item = items[i];
-      args[argsIndex++] = item.key;
-      args[argsIndex++] = item.path;
-      args[argsIndex++] = transformRedisJsonArgument(item.value);
+      parser.pushKey(items[i].key);
+      parser.pushVariadic([items[i].path, transformRedisJsonArgument(items[i].value)]);
     }
-
-    return args;
   },
+  transformArguments(items: Array<JsonMSetItem>) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/NUMINCRBY.spec.ts b/packages/json/lib/commands/NUMINCRBY.spec.ts
index d0bffd2bd2a..b438069e80f 100644
--- a/packages/json/lib/commands/NUMINCRBY.spec.ts
+++ b/packages/json/lib/commands/NUMINCRBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import NUMINCRBY from './NUMINCRBY';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.NUMINCRBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      NUMINCRBY.transformArguments('key', '$', 1),
+      parseArgs(NUMINCRBY, 'key', '$', 1),
       ['JSON.NUMINCRBY', 'key', '$', '1']
     );
   });
diff --git a/packages/json/lib/commands/NUMINCRBY.ts b/packages/json/lib/commands/NUMINCRBY.ts
index 65cc7db68a9..e6815a49539 100644
--- a/packages/json/lib/commands/NUMINCRBY.ts
+++ b/packages/json/lib/commands/NUMINCRBY.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, ArrayReply, NumberReply, DoubleReply, NullReply, BlobStringReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, path: RedisArgument, by: number) {
-    return ['JSON.NUMINCRBY', key, path, by.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, path: RedisArgument, by: number) {
+    parser.push('JSON.NUMINCRBY');
+    parser.pushKey(key);
+    parser.pushVariadic([path, by.toString()]);
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, by: number) { return [] },
   transformReply: {
     2: (reply: UnwrapReply<BlobStringReply>) => {
       return JSON.parse(reply.toString()) as number | Array<null | number>;
diff --git a/packages/json/lib/commands/NUMMULTBY.spec.ts b/packages/json/lib/commands/NUMMULTBY.spec.ts
index 9767c2b0979..24ee932e952 100644
--- a/packages/json/lib/commands/NUMMULTBY.spec.ts
+++ b/packages/json/lib/commands/NUMMULTBY.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import NUMMULTBY from './NUMMULTBY';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.NUMMULTBY', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      NUMMULTBY.transformArguments('key', '$', 2),
+      parseArgs(NUMMULTBY, 'key', '$', 2),
       ['JSON.NUMMULTBY', 'key', '$', '2']
     );
   });
diff --git a/packages/json/lib/commands/NUMMULTBY.ts b/packages/json/lib/commands/NUMMULTBY.ts
index 255685a9a50..07f16ad150f 100644
--- a/packages/json/lib/commands/NUMMULTBY.ts
+++ b/packages/json/lib/commands/NUMMULTBY.ts
@@ -1,11 +1,15 @@
 import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
 import NUMINCRBY from './NUMINCRBY';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, path: RedisArgument, by: number) {
-    return ['JSON.NUMMULTBY', key, path, by.toString()];
+  parseCommand(parser: CommandParser, key: RedisArgument, path: RedisArgument, by: number) {
+    parser.push('JSON.NUMMULTBY');
+    parser.pushKey(key);
+    parser.pushVariadic([path, by.toString()]);
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, by: number) { return [] },
   transformReply: NUMINCRBY.transformReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/OBJKEYS.spec.ts b/packages/json/lib/commands/OBJKEYS.spec.ts
index dc984cb2ce9..0d2176248e4 100644
--- a/packages/json/lib/commands/OBJKEYS.spec.ts
+++ b/packages/json/lib/commands/OBJKEYS.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJKEYS from './OBJKEYS';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.OBJKEYS', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        OBJKEYS.transformArguments('key'),
+        parseArgs(OBJKEYS, 'key'),
         ['JSON.OBJKEYS', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        OBJKEYS.transformArguments('key', {
+        parseArgs(OBJKEYS, 'key', {
           path: '$'
         }),
         ['JSON.OBJKEYS', 'key', '$']
diff --git a/packages/json/lib/commands/OBJKEYS.ts b/packages/json/lib/commands/OBJKEYS.ts
index fb8ae6bb034..d0222fe257e 100644
--- a/packages/json/lib/commands/OBJKEYS.ts
+++ b/packages/json/lib/commands/OBJKEYS.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, BlobStringReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonObjKeysOptions {
   path?: RedisArgument;
@@ -7,14 +8,13 @@ export interface JsonObjKeysOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, options?: JsonObjKeysOptions) {
-    const args = ['JSON.OBJKEYS', key];
-
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonObjKeysOptions) {
+    parser.push('JSON.OBJKEYS');
+    parser.pushKey(key);
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonObjKeysOptions) { return [] },
   transformReply: undefined as unknown as () => ArrayReply<BlobStringReply> | ArrayReply<ArrayReply<BlobStringReply> | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/OBJLEN.spec.ts b/packages/json/lib/commands/OBJLEN.spec.ts
index 8f616107fd5..a5664a4d6bc 100644
--- a/packages/json/lib/commands/OBJLEN.spec.ts
+++ b/packages/json/lib/commands/OBJLEN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import OBJLEN from './OBJLEN';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.OBJLEN', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        OBJLEN.transformArguments('key'),
+        parseArgs(OBJLEN, 'key'),
         ['JSON.OBJLEN', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        OBJLEN.transformArguments('key', {
+        parseArgs(OBJLEN, 'key', {
           path: '$'
         }),
         ['JSON.OBJLEN', 'key', '$']
diff --git a/packages/json/lib/commands/OBJLEN.ts b/packages/json/lib/commands/OBJLEN.ts
index f9c45e336ad..c68389300d9 100644
--- a/packages/json/lib/commands/OBJLEN.ts
+++ b/packages/json/lib/commands/OBJLEN.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, NumberReply, ArrayReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonObjLenOptions {
   path?: RedisArgument;
@@ -7,14 +8,13 @@ export interface JsonObjLenOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options?: JsonObjLenOptions) {
-    const args = ['JSON.OBJLEN', key];
-
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonObjLenOptions) {
+    parser.push('JSON.OBJLEN');
+    parser.pushKey(key);
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonObjLenOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/RESP.spec.ts b/packages/json/lib/commands/RESP.spec.ts
index 6dfc3360326..2cb3e9e15c3 100644
--- a/packages/json/lib/commands/RESP.spec.ts
+++ b/packages/json/lib/commands/RESP.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
-import { transformArguments } from './RESP';
+import RESP from './RESP';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('RESP', () => {
     describe('transformArguments', () => {
         it('without path', () => {
             assert.deepEqual(
-                transformArguments('key'),
+                parseArgs(RESP, 'key'),
                 ['JSON.RESP', 'key']
             );
         });
 
         it('with path', () => {
             assert.deepEqual(
-                transformArguments('key', '$'),
+                parseArgs(RESP, 'key', '$'),
                 ['JSON.RESP', 'key', '$']
             );
         });
diff --git a/packages/json/lib/commands/RESP.ts b/packages/json/lib/commands/RESP.ts
index fcf54cd3537..c3051be8a7b 100644
--- a/packages/json/lib/commands/RESP.ts
+++ b/packages/json/lib/commands/RESP.ts
@@ -1,15 +1,18 @@
-export const FIRST_KEY_INDEX = 1;
-
-export function transformArguments(key: string, path?: string): Array<string> {
-    const args = ['JSON.RESP', key];
-
-    if (path) {
-        args.push(path);
-    }
-
-    return args;
-}
+import { Command, RedisArgument } from "@redis/client/dist/lib/RESP/types";
+import { CommandParser } from "@redis/client/dist/lib/client/parser";
 
 type RESPReply = Array<string | number | RESPReply>;
 
-export declare function transformReply(): RESPReply;
+export default {
+    FIRST_KEY_INDEX: 1,
+    IS_READ_ONLY: true,
+    parseCommand(parser: CommandParser, key: RedisArgument, path?: string) {
+      parser.push('JSON.RESP');
+      parser.pushKey(key);
+      if (path !== undefined) {
+        parser.push(path);
+      }
+    },
+    transformArguments(key: RedisArgument, path?: string): Array<string> { return [] },
+    transformReply: undefined as unknown as () => RESPReply
+  } as const satisfies Command;
\ No newline at end of file
diff --git a/packages/json/lib/commands/SET.spec.ts b/packages/json/lib/commands/SET.spec.ts
index 15e27073281..7bd927f08e4 100644
--- a/packages/json/lib/commands/SET.spec.ts
+++ b/packages/json/lib/commands/SET.spec.ts
@@ -1,26 +1,27 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import SET from './SET';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.SET', () => {
   describe('transformArguments', () => {
     it('transformArguments', () => {
       assert.deepEqual(
-        SET.transformArguments('key', '$', 'json'),
+        parseArgs(SET, 'key', '$', 'json'),
         ['JSON.SET', 'key', '$', '"json"']
       );
     });
 
     it('NX', () => {
       assert.deepEqual(
-        SET.transformArguments('key', '$', 'json', { NX: true }),
+        parseArgs(SET, 'key', '$', 'json', { NX: true }),
         ['JSON.SET', 'key', '$', '"json"', 'NX']
       );
     });
 
     it('XX', () => {
       assert.deepEqual(
-        SET.transformArguments('key', '$', 'json', { XX: true }),
+        parseArgs(SET, 'key', '$', 'json', { XX: true }),
         ['JSON.SET', 'key', '$', '"json"', 'XX']
       );
     });
diff --git a/packages/json/lib/commands/SET.ts b/packages/json/lib/commands/SET.ts
index 78aea4b3545..44bb6044d07 100644
--- a/packages/json/lib/commands/SET.ts
+++ b/packages/json/lib/commands/SET.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, SimpleStringReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
 import { RedisJSON, transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonSetOptions {
   condition?: 'NX' | 'XX';
@@ -16,23 +17,25 @@ export interface JsonSetOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(
+  parseCommand(
+    parser: CommandParser,
     key: RedisArgument,
     path: RedisArgument,
     json: RedisJSON,
     options?: JsonSetOptions
   ) {
-    const args = ['JSON.SET', key, path, transformRedisJsonArgument(json)];
+    parser.push('JSON.SET');
+    parser.pushKey(key);
+    parser.pushVariadic([path, transformRedisJsonArgument(json)]);
 
     if (options?.condition) {
-      args.push(options?.condition);
+      parser.push(options?.condition);
     } else if (options?.NX) {
-      args.push('NX');
+      parser.push('NX');
     } else if (options?.XX) {
-      args.push('XX');
+      parser.push('XX');
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, path: RedisArgument, json: RedisJSON, options?: JsonSetOptions) { return [] },
   transformReply: undefined as unknown as () => SimpleStringReply<'OK'> | NullReply
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/STRAPPEND.spec.ts b/packages/json/lib/commands/STRAPPEND.spec.ts
index 0d8bdb57185..ebd539130e1 100644
--- a/packages/json/lib/commands/STRAPPEND.spec.ts
+++ b/packages/json/lib/commands/STRAPPEND.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import STRAPPEND from './STRAPPEND';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.STRAPPEND', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        STRAPPEND.transformArguments('key', 'append'),
+        parseArgs(STRAPPEND, 'key', 'append'),
         ['JSON.STRAPPEND', 'key', '"append"']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        STRAPPEND.transformArguments('key', 'append', {
+        parseArgs(STRAPPEND, 'key', 'append', {
           path: '$'
         }),
         ['JSON.STRAPPEND', 'key', '$', '"append"']
diff --git a/packages/json/lib/commands/STRAPPEND.ts b/packages/json/lib/commands/STRAPPEND.ts
index 12ee7cc394c..395a98fecd6 100644
--- a/packages/json/lib/commands/STRAPPEND.ts
+++ b/packages/json/lib/commands/STRAPPEND.ts
@@ -1,5 +1,6 @@
 import { RedisArgument, Command, NullReply, NumberReply, ArrayReply } from '@redis/client/dist/lib/RESP/types';
 import { transformRedisJsonArgument } from '.';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonStrAppendOptions {
   path?: RedisArgument;
@@ -8,15 +9,16 @@ export interface JsonStrAppendOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, append: string, options?: JsonStrAppendOptions) {
-    const args = ['JSON.STRAPPEND', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, append: string, options?: JsonStrAppendOptions) {
+    parser.push('JSON.STRAPPEND');
+    parser.pushKey(key);
 
     if (options?.path !== undefined) {
-      args.push(options.path);
+      parser.push(options.path);
     }
 
-    args.push(transformRedisJsonArgument(append));
-    return args;
+    parser.push(transformRedisJsonArgument(append));
   },
+  transformArguments(key: RedisArgument, append: string, options?: JsonStrAppendOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NullReply | NumberReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/STRLEN.spec.ts b/packages/json/lib/commands/STRLEN.spec.ts
index e058e48a635..b6881b5bd52 100644
--- a/packages/json/lib/commands/STRLEN.spec.ts
+++ b/packages/json/lib/commands/STRLEN.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import STRLEN from './STRLEN';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.STRLEN', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        STRLEN.transformArguments('key'),
+        parseArgs(STRLEN, 'key'),
         ['JSON.STRLEN', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        STRLEN.transformArguments('key', {
+        parseArgs(STRLEN, 'key', {
           path: '$'
         }),
         ['JSON.STRLEN', 'key', '$']
diff --git a/packages/json/lib/commands/STRLEN.ts b/packages/json/lib/commands/STRLEN.ts
index 3b514d9caba..8b457378c59 100644
--- a/packages/json/lib/commands/STRLEN.ts
+++ b/packages/json/lib/commands/STRLEN.ts
@@ -1,4 +1,5 @@
 import { RedisArgument, ArrayReply, NumberReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonStrLenOptions {
   path?: RedisArgument;
@@ -7,14 +8,14 @@ export interface JsonStrLenOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options?: JsonStrLenOptions) {
-    const args = ['JSON.STRLEN', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonStrLenOptions) {
+    parser.push('JSON.STRLEN');
+    parser.pushKey(key);
 
     if (options?.path) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonStrLenOptions) { return [] },
   transformReply: undefined as unknown as () => NumberReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/TOGGLE.spec.ts b/packages/json/lib/commands/TOGGLE.spec.ts
index c8a78877906..173c7708f4a 100644
--- a/packages/json/lib/commands/TOGGLE.spec.ts
+++ b/packages/json/lib/commands/TOGGLE.spec.ts
@@ -1,11 +1,12 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TOGGLE from './TOGGLE';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.TOGGLE', () => {
   it('transformArguments', () => {
     assert.deepEqual(
-      TOGGLE.transformArguments('key', '$'),
+      parseArgs(TOGGLE, 'key', '$'),
       ['JSON.TOGGLE', 'key', '$']
     );
   });
diff --git a/packages/json/lib/commands/TOGGLE.ts b/packages/json/lib/commands/TOGGLE.ts
index 2a8df3eba36..5b66e89f4ba 100644
--- a/packages/json/lib/commands/TOGGLE.ts
+++ b/packages/json/lib/commands/TOGGLE.ts
@@ -1,10 +1,14 @@
 import { RedisArgument, ArrayReply, NumberReply, NullReply, Command, } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: false,
-  transformArguments(key: RedisArgument, path: RedisArgument) {
-    return ['JSON.TOGGLE', key, path];
+  parseCommand(parser: CommandParser, key: RedisArgument, path: RedisArgument) {
+    parser.push('JSON.TOGGLE');
+    parser.pushKey(key);
+    parser.push(path);
   },
+  transformArguments(key: RedisArgument, path: RedisArgument) { return [] },
   transformReply: undefined as unknown as () => NumberReply | NullReply | ArrayReply<NumberReply | NullReply>
 } as const satisfies Command;
diff --git a/packages/json/lib/commands/TYPE.spec.ts b/packages/json/lib/commands/TYPE.spec.ts
index 103ce59de6e..1b6ad109816 100644
--- a/packages/json/lib/commands/TYPE.spec.ts
+++ b/packages/json/lib/commands/TYPE.spec.ts
@@ -1,19 +1,20 @@
 import { strict as assert } from 'node:assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import TYPE from './TYPE';
+import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
 
 describe('JSON.TYPE', () => {
   describe('transformArguments', () => {
     it('simple', () => {
       assert.deepEqual(
-        TYPE.transformArguments('key'),
+        parseArgs(TYPE, 'key'),
         ['JSON.TYPE', 'key']
       );
     });
 
     it('with path', () => {
       assert.deepEqual(
-        TYPE.transformArguments('key', {
+        parseArgs(TYPE, 'key', {
           path: '$'
         }),
         ['JSON.TYPE', 'key', '$']
diff --git a/packages/json/lib/commands/TYPE.ts b/packages/json/lib/commands/TYPE.ts
index 68c5d850ebf..4449304ee80 100644
--- a/packages/json/lib/commands/TYPE.ts
+++ b/packages/json/lib/commands/TYPE.ts
@@ -1,4 +1,5 @@
 import { NullReply, BlobStringReply, ArrayReply, Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
+import { CommandParser } from '@redis/client/dist/lib/client/parser';
 
 export interface JsonTypeOptions {
   path?: RedisArgument;
@@ -7,15 +8,15 @@ export interface JsonTypeOptions {
 export default {
   FIRST_KEY_INDEX: 1,
   IS_READ_ONLY: true,
-  transformArguments(key: RedisArgument, options?: JsonTypeOptions) {
-    const args = ['JSON.TYPE', key];
+  parseCommand(parser: CommandParser, key: RedisArgument, options?: JsonTypeOptions) {
+    parser.push('JSON.TYPE');
+    parser.pushKey(key);
 
     if (options?.path) {
-      args.push(options.path);
+      parser.push(options.path);
     }
-
-    return args;
   },
+  transformArguments(key: RedisArgument, options?: JsonTypeOptions) { return [] },
   transformReply: {
     2: undefined as unknown as () => NullReply | BlobStringReply | ArrayReply<BlobStringReply>,
     // TODO: ?!??!