Repository navigation
Support .noderc or similar file-based initialization configurations? #53787
Description
Activity
I’ve proposed this in the past, such as in #49148 (comment) and https://github.com/orgs/nodejs/discussions/44975#discussioncomment-3868855. The short version is that I think we need a config file, such as
node.config.jsonor possibly a section withinpackage.json, and I think it needs to include all of the same options thatNODE_OPTIONSincludes. This will handle the use case of the test runner config file and any other features that have configuration that’s complicated enough to want to specify in a file, or have the configuration be updated by automation such as in the hooks case.The recent
.envfile support was meant as a bridge to this; that effort got us the ability to parse JSON files without needing to start V8, so therefore we can parse a config file that includes V8 options early enough for them to take effect. The work toward supportingNODE_OPTIONSwithin.envfiles was meant to lay the groundwork for this.So yes, I do think we need a config file, and it should support all of Node’s configuration (or at least as much as is in
NODE_OPTIONS). That probably means it needs to be in JSON or some other format that we can parse without V8. A simple schema could probably be something like:{ "options": { // Keys can be any flag available to NODE_OPTIONS, camelcased "import": "tsx", "experimentalRequireModule": true } }Or the same within a
nodejsfield inpackage.jsonif that’s preferable. Ideally this file is loaded by default if it exists, and we could have a flag like--configto backport it for older lines (or maybe this is a reason to use a key inpackage.json, if adding this new key isn’t considered a breaking change). I think it might be slightly preferable to have a dedicated file for this rather thanpackage.jsonfield because a project might have multiplepackage.jsons and we could separately define the configuration file and then Node knows where to look for it, but I don’t feel strongly if others can explain whypackage.jsonis preferable and won’t have issues.Another consideration is conditions; should a single file support multiple values based on condition, so you could do something like
node --config=node.config.json --condition=development entry.jsand it loads certain config values related to the development condition.Reacted by Aviv Keller, Abhijeet Prasad, Tim Fish, Théo LUDWIG and Ricardo Fernández Serrata- addedcliIssues and PRs related to the Node.js command-line interface.Issues and PRs related to the Node.js command-line interface.
on Jul 9, 2024 +1, but I am very much against JSON for the format, mainly because it doesn't support comments.
Reacted by James Sumners, Stephen Belanger, Marco Ippolito, Jacob Smith, fregante, Ricardo Fernández Serrata, Darcy Clarke and Eric CorneliusReacted by Jon Schlinkert+1 here as well. And I agree with @targos.
If we don't create a custom format, I would choose YAML or TOML.It's important that the format be easily editable by other tools, such as those registering hooks. Anything other than comment-less JSON means that those tools need a dependency, unless we create a new builtin for the format.
We've had
package.jsonfor years and it's been acceptable. A bit annoying that it doesn't support comments or trailing commas, for sure, but it's easily editable both by hand and by tools. See the recent strongly negative reaction to Bun allowing comments inpackage.json; that's why interoperability is important.Reacted by Tim Fish, Abhijeet Prasad, João Lenon, Théo LUDWIG, Jon Schlinkert and Ricardo Fernández SerrataThat was my idea. Have a new builtin format.
TBH, I always thought Node should support YAML natively since it's quite pervasive.If we want to be aligned with npmrc, https://www.npmjs.com/package/ini can be an option too (there are other native INI parsers too, like https://github.com/benhoyt/inih)
and it should support all of Node’s configuration (or at least as much as is in NODE_OPTIONS
I think we should consider supporting a subset and evaluate them on a case by case basis. NODE_OPTIONS are about “flat” command line options, some of them per-process, some of them per-isolate, some of them per-environment. I think for the file based config we need something better than a flat structure to avoid the NODE_OPTIONS and execArgv inheritance validity problem again, and it will take time to address the hierarchical problem for all the possible configs (I also think the current internal classification of options may still contain quite some errors to be surfaced to the config directly)
Reacted by Aviv Keller and Ricardo Fernández SerrataI am in favor of a standalone file with the following opinions:
- I have never enjoyed adding configuration to
package.json. It just feels wrong to me. It's a package manifest, not program configuration. - JSON is the native format for the language we are working in, but if we are parsing prior to V8, no need to stick to that as a limitation.
- Comments are a necessary possibility for configuration files.
- INI, and in particular npm's wacko variant of it, is not ideal.
- Supporting JSON, YAML, and maybe TOML would be my preference.
- Config files should require a proper extension so that tooling (and the implementation) can easily detect the format:
.noderc.json,.noderc.yaml,.noderc.yml, and.noderc.toml.
Reacted by Stephen Belanger, Aviv Keller, fregante, Asım Tahir and Ricardo Fernández Serrata- I have never enjoyed adding configuration to
I'm a fan of KDL.
I feel like the need for a config file format parser if we go with non-json (which we should because comments) suggests it might be of value to also have something built in for generalized parsing, which could also be helpful for stream processing in many cases. I wonder if we should take that into consideration when building whatever format parser we might need. 🤔
Reacted by Ricardo Fernández SerrataWhatever format we read needs to be parseable in C++. We added simdjson to be able to parse JSON in C++, so that’s an option. The addition of
--env-filegave us the ability to parse essentially the INI format.Another option is to expand out
.envfiles into essentially configuration files, by creating new environment variables for every option. So my example above could become an.envfile like:# node.config.env NODE_OPTION_IMPORT=tsx NODE_OPTION_EXPERIMENTAL_REQUIRE_MODULE=true
And it gets loaded via
node --env-file=node.config.env app.jsjust like any other.envfile, and the options are read from these new environment variables. This has the benefit of automatically being inherited into child processes wheneverenvis passed down. We already haveutil.parseEnvto parse this into an object, and we could add a corresponding setter method to help convert such objects back into INI format strings.Reacted by Ricardo Fernández SerrataI think making this opt-in would bring us back to square one, especially if the surface is limited to a flat list, then it’s not really too different than .env; but that’s also inconsistent with the broader software convention of loading a rc file by default.
this has the benefit of automatically being inherited into child processes whenever env is passed down.
I think this is actually a flaw, not a benefit, because a flat list of environment variables is not a great way for inherited configurations, see #41103 - child workers and contexts need granular control of configurations.
Reacted by Ricardo Fernández SerrataI was thinking that whatever config file we choose would be loaded automatically as a semver-major change, and a flag could specify it for older Node versions. A flag might be used for the latest version too in case the user wants to specify a file that’s not the default filename or location.
I’m not sure what about #41103 involves any of this. We should just filter out options that don’t make sense to inherit, both currently to resolve that issue and in the future when we add a proper config file. We should do that filtering however the problematic options are defined, such as via environment variables or
NODE_OPTIONSor via a file. Users already have ways to exert granular control of what flags and/or environment variables are passed into child processes or workers, viaexecArgvorenv.We all hate json. No comments, excessive quoting, no multi line strings, no trailing commas, etc.
But:
- it's specified very clearly (unlike ini, which is not specified at all)
- it's built into the language
- It's FAST, like, omg wow, much faster than yaml or toml, not even close. Even jsonc is much slower.
- vim and vscode can auto format a js object into json with a keyboard shortcut
- We could reserve the
"//"key to be explicitly ignored (like npm has done) and use that for comments. - Every node program already has a json file just sitting in the root, which node already loads for a bunch of stuff, with very clear and unambiguous semantics.
- it can never change and has one version (unlike yaml and toml)
A
nodejssection inpackage.jsonis ideal. Make it so that if it's a string, then that's the name of a file to load, like many other tools do. Then we don't have to agree on the perfect spelling for the filename.The beauty of json is that no one has to agree on very much.
Reacted by Colin Ihrig, Jordan Harband, Abhijeet Prasad, Théo LUDWIG, Jacob Smith, Carlos Fuentes and Ricardo Fernández SerrataReacted by Jacob SmithA nodejs section in package.json is ideal. Make it so that if it's a string, then that's the name of a file to load, like many other tools do. Then we don't have to agree on the perfect spelling for the filename.
I am leaning towards "a field specified in package.json pointing to a file" too primarily because to load this by default, it adds overhead to the startup to probe the file system; And since we already probe the file system for package.json, the overhead of probing another field in it would be the smallest.
But I do like to see a fixed (at least base) name of the file, because I like the concept of universally recognizable manifest of projects, just like when I check out a JS project/package, if I want to see dependency information I go to package.json, if I want to see TypeScript information I go to tsconfig.json, if I want to see their eslint configs I go to any file that contains the word eslint etc. Maybe something we can do is to support multiple formats (like what eslint does), and JSON would be the first to support, but they all have the same basename, and people just pick the format they like, provided that we do add support for other formats later on.
Reacted by Michaël Zasso, Jordan Harband, Clemens Stolle, Marco Ippolito, Stephen Belanger and Ricardo Fernández Serrata61 remaining items
- added a commit that references this issue
on May 6, 2025 - added 2 commits that reference this issue
on May 14, 2025 - added 12 commits that reference this issue
on May 16, 2025
In #52219 it was mentioned that for APM use cases it would be nice to have a way to register loaders without using command line flags. It occurred to me maybe what we need is an initialization config similar to the rc files out there for various applications.
For example in my
.lldbinitI have these that extend LLDB to help me debugIt seems this is serving the same use case as the Node.js loader registration - run some scripts or register some plugin to Node.js before you actually start running it.
For loading loaders, I guess we can support something like a
.nodercthat is discovered when users start running Node.js, or make that part ofpackage.json, which allows registering certain hooks before the actual application code is run. For example in the case of package.json, I guess the project pacakge.json would include something like this:If we want something more flexible than "just loading some scripts" though, I guess a dedicated rc file would be easier to use than package.json.
cc @timfish @nodejs/loaders