Repository navigation
Remove restriction on '/' prefixes #49449
Description
Activity
To be clear, this is about direct import specifiers (https://nodejs.org/api/esm.html#esm_import_specifiers), e.g.:
// imports file:///usr/local/etc/mytool.config.mjs, assuming import.meta.url has file:// protocol. import config from '/usr/local/etc/mytool.config.mjs';
I think that makes sense. Given
"imports", I don't see a strong reason to reserve design space here (IIRC package-relative was the only thing ever discussed for this spot).Reacted by Derek LewisWait, why would we want to allow this? What are the use cases for root-absolute specifiers?
I can't conceive of a time in CJS where requiring from a /-prefixed path wasn't a bug (or bad design, as was later revealed when it was ran on a different machine).
@ljharb because it adds consistency and I cannot think of a reason to disallow these specifiers on concrete concerns if we are not reserving them for future features. Any future feature using those prefixes not matching the generally accepted behavior of URL resolution would be bad so it isn't like we can use the feature for other purposes beyond pinning to some kind of root.
I absolutely agree that if
/is allowed as a non-//prefix, it would have to function as an absolute path, but I don't think "consistency" is a good argument to enable something that is almost always a footgun.Reacted by Eric Blade and ExE Boss@ljharb why is it a footgun? is there clear reasoning here or is it just a linting issue?
It's a footgun because it's not project-portable or machine-portable; any time you have code that uses
/, it's highly likely to break on someone else's machine (including a different docker image, host vs guest, if you migrate from one computer to a new one, etc).Reacted by Eric Blade and ExE Boss@ljharb that statement is true for any given one off script that isn't installed via a package manager and uses bare specifiers for things. I do see utility in various things like the ability to
import '/etc/config/foo.json';regardless.Reacted by Jan Olaf Martin and Derek LewisI have definitely imported things using absolute paths. If it's top-level application code that will only ever run in a docker container, I don't see anything wrong with importing something (like a config file) from an absolute path. I haven't seen strong evidence that this behavior caused issues in
requirebut have seen people use it there for - what I would consider - valid reasons. But that's admittedly anecdotal.Reacted by Derek LewisAFAIK (note: I don't use node as a web server) Node.js doesn't have a directory like this, so we can't really mimic this behavior.
Node.js does have a "directory" like this - because modules in node use the
file:protocol and host-relative resolution of/works the same here as it does in HTTP URLs. Resolving/zapprelative tofile:///foo/baris well-defined across platforms. Most importantly it's not generally a path relative to the system root, not even on OSs with POSIX paths. Resolving/a%20b.jswill not resolve to the file with POSIX path/a%20b.js. It will resolve to a "completely" different path:/a b.js. Those are two different files.The fact that Apache may serve some of the
http:URLs from some directory on disk is a special case with one particular configuration. E.g. Apache could serve some URLs from a constant string in the config or from running a CGI script or from various directories depending on URL patterns. In terms of resolution, that shouldn't really matter.That node's implementation uses URLs doesn't mean that node module specifiers are conceptually URLs - they're file paths (which happen to be a subset of URLs).
@ljharb the file specifiers are URLs, not paths, they do have fragments taken into consideration.
I realize they are URLs. I'm saying most users will never think of them that way.
That node's implementation uses URLs doesn't mean that node module specifiers are conceptually URLs - they're file paths (which happen to be a subset of URLs).
I think it would be dangerous if we allow users to think that they are file paths. If allowing
/reinforces that notion, then I'd consider it an argument to keep/"forbidden". Code likeimport(path.resolve(filename)))may look at first glance like it should work but it will not be portable or safe. It will only work if bothfilenameand the working directory happen to only contain URL-safe characters that are interpreted the same way in both filenames andfile:URLs. True for many common filenames but not true for arbitrary filenames.Reacted by Jordan Harband and ExE Boss@DerekNonGeneric that's because MDN is geared towards the web, not node, and on the web, that's a domain-relative URL.
I feel very strongly that if a leading
/is allowed, it can only ever mean "the filesystem root", because that's what it already means in CJS.I feel very strongly that if a leading / is allowed, it can only ever mean "the filesystem root", because that's what it already means in CJS.
Yes, for
file:referrers, it would roughly be "the file system root". But if we explain it as "just like CommonJS", we're asking for trouble. Because while it may be relative to the file system root, it's not a file system path (!). The following will load two different files, even though the specifiers are equal and both interpreted relative to the file system root:require('/tmp/a%20b.js'); // the file "/tmp/a%20b.js" ("file:///tmp/a%2520b.js") import('/tmp/a%20b.js'); // the file "/tmp/a b.js" ("file:///tmp/a%20b.js")
If we don't think people can differentiate between those two different paths, maybe we shouldn't allow a leading slash in
import.P.S.: I think we can expect people to think of imports as URL-based longer term. There's way more JavaScript-first devs than node.js-first devs and hopefully the former will become used to thinking in URLs when using
import.Reacted by Derek Lewis and ExE Boss@DerekNonGeneric that seems like you just want to run a
chrootaround node, not that node would actually need to do anything.Reacted by Jan Olaf MartinWait, what does
/in CJS on Windows map to now??Right, but "c:" isn't necessarily the fs root on windows - where linux has
/, and all volumes are mounted under that, windows has up to 26 (i think) volume roots, and i'm not aware there is any pathable location that contains all of them.Perhaps it maps to the root of the working directory's drive?
that's not cross-platform, I don't understand how that is the suggestion here.
It works on everywhere but windows natively and windows has workarounds for this via cygwin, windows subsystem for linux, etc. The point was that the request doesn't seem to be something that node needs to specifically handle, and the details of chroot are quite complex.
@DerekNonGeneric there is no point that I stated that windows is second class.
Reacted by Derek LewisAfter reading the other recent thread, I think my bigger concern is with *nix platforms where people may confuse
/some/file/url/pathwith/some/os/file/nameand then run into issues with the different encoding. It seemed very hard to get the point across that there are (some) practical differences between the two because they look so similar.I would be in favor of a clear warning in our resolver when resolving a host-relative URL against a
file:URL, suggesting people use an explicit protocol. Not a really strong opinion (there's plenty of common file naming patterns where it's fine) but it may be worth it.- addedmoduleIssues and PRs related to the module subsystem.Issues and PRs related to the module subsystem.
on Sep 1, 2023 github-actions commented
on Jun 27, 2026 on Jun 27, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- 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 27, 2026 github-actions commented
on Jul 28, 2026 on Jul 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
Given that we have self referential packages, and
"imports"inpackage.json. In addition since//is reserved I think we should remove the reservation since it will by the default URL parser be treated as protocol relative.