Repository navigation
Should node support subcommands? #53483
Description
Activity
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.cliIssues and PRs related to the Node.js command-line interface.Issues and PRs related to the Node.js command-line interface.
on Jun 17, 2024 I've voiced concerns about this various times in the past, perhaps most recently in this comment. Don't get me wrong, subcommands are great, and if we were to redesign Node.js from scratch we likely should use them. However, ...
I have reason to believe that a significant number of users rely on the fact that
node testruns eithertest.jsortest/index.js, and the same is likely true fornode run. So while semver-major releases technically allow us to break things, I think this would cause significant breakage. There's probably many semi-maintained npm modules that usenode test(or variations thereof) as their npmtestscript.More generally, accepting either a positional argument or a subcommand in the same location is an anti-pattern in my mind. We unfortunately already have
node inspect, so Node.js is already following something that I'd consider an anti-pattern, but that shouldn't be a loophole for us to further commit to that anti-pattern.The only semi-reasonable way I see is to fully deprecate
node xyz, wherexyzwould usually cause the execution of whateverxyzresolves to. Of course, this would be a huge breaking change and would likely take years, but anything less than this will introduce more and more inconsistencies, and each new subcommand would cause new breakage and deprecation cycles.Reacted by Moshe AtlowThe only semi-reasonable way I see is to fully deprecate node xyz, where xyz would usually cause the execution of whatever xyz resolves to. Of course, this would be a huge breaking change and would likely take years, but anything less than this will introduce more and more inconsistencies, and each new subcommand would cause new breakage and deprecation cycles.
why would that take years?
We can doc-only deprecate the current behavior right now, and releasing that would take days to weeks. But actually moving
node xyzto end-of-life seems like a huge breaking change to me. (Then again, some project members are more open to rapidly breaking things than myself, so maybe it would just take two semver-majors or so.)We could take some pragmatic, not very elegant steps to avoid reaching end-of-life status, e.g., by still allowing
node xyzwheneverxyzlooks like a path (e.g., contains a file extension or a directory separator). But in any case, we'll break the very basics of how people run JavaScript files with Node.js.Reacted by Moshe Atlow and Richard LauBut in any case, we'll break the very basics of how people run JavaScript files with Node.js.
I think, for example, that preventing
node xyzfrom runningxyzwould stop Node.js shell scripts (i.e. those that begin#!/usr/bin/env node ...) from working.
Reacted by Tobias Nießen and Benjamin GruenbaumFor files with the same name as commands, the project could adopt what many CLIs do, which is if a value is within quotes, don't treat as a CLI flag (IE
"--hello"is a file, while--hellois a CLI argument)I'm not aware of anything else that does this, but IMO this would be terribly confusing to users -- in many cases the quotes would be processed by the shell and wouldn't be seen by the program being run (i.e.
node).Reacted by Tobias NießenI think, for example, that preventing node xyz from running xyz would stop Node.js shell scripts
why would adding subcommands break hashbang? I am not following
I think, for example, that preventing node xyz from running xyz would stop Node.js shell scripts
why would adding subcommands break hashbang? I am not following
Because if you have a file called
xyzthat begins:#!/usr/bin/env node ...that has execute permissions and you run it, e.g.
xyzit will end up running the equivalent of
node xyzReacted by Tobias Nießen, Moshe Atlow, Joyee Cheung and Chengzhong WuI'm +1 on making this breaking change. I think the UX for cli flags are really bad that even I have some trouble understanding if feature X is working with feature Y.
Reacted by Chemi Atlow, Vas Sudanagunta, Jacob Smith and Pietro Marchinigithub-actions commented
on Dec 16, 2024 on Dec 16, 2024 – with GitHub ActionsContributorMore actionsThere has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the never-stale
Issues and PRs exempt from automated stale handling. label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Dec 16, 2024 - removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Dec 16, 2024 github-actions commented
on Jun 15, 2025 on Jun 15, 2025 – with GitHub ActionsContributorMore actionsThere has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the never-stale
Issues and PRs exempt from automated stale handling. label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 15, 2025 - addednever-staleIssues and PRs exempt from automated stale handling.Issues and PRs exempt from automated stale handling.and removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 15, 2025 While I think I'm ok with the breaking change wrt to
node xyz, an alternative to consider is having separate commands:node <script, even if "test"> node-test <test script> node-inspect <script to debug> node-run <pkg script>
If
node testinvoked thetestsubcommand, then one could usenode -- testto force "test" to be treated as an argument.Another option, that is backward compatible, is for
node testto work as it does today IFFtestresolves to a script, and otherwise to invoke the test subcommand.If you think of the test subcommand as the built-in default resolution for
node test, user overridable by the presence of a script namedtestin the cwd, there is both rhyme and reason to this behavior.Why bother? Because the current node CLI is unwieldy and will only get worse. For example see discussions under #51384 and nodejs/test-runner#13.
Reacted by Domenic Denicola and Jacob Smith
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriaged
What is the problem this feature will solve?
currently, node's cli interface is pretty simple and lean,
it mainly accepts flags that start with two dashes, or sometimes a single dash for some aliases.
additionally, many flags depend on each other or imply using another flag.
now that more and more flags are added to node, (and each new flag is heavily considered before adding to avoid options bloat), I propose we support a more complex cli interface with sub-commands.
this issue has come up before when adding
node --run, and to avoid blocking that - the discussion was postponed, so I went ahead and opened this issue.If I recall, the main concern was
node runornode testis a breaking change since it today runsnode run.jsornode test.jsaccordingly - that can be addressed with releasing this gradually as semver-major with a deprecation warning for a few versions prior to the actual changesome groups/clusters of commands that might fit using sub commands:
node --runnode --watch,--watch-pathnode --testnode --build-snapshotWhat is the feature you are proposing to solve the problem?
N/A
What alternatives have you considered?
No response