node js: does fs.rename overwrite file if already exists

It looks like the function fs.rename() provides the same functionality that the Linux rename(2) command provides (source: Move File in ExpressJS/NodeJS). Having said this, if you look at the docs for the Linux rename(2) command, they say that if the file name you are renaming to already exists, the existing file name will be replaced and overwritten (source: http://linux.die.net/man/2/rename)


nodejs’s fs.rename() overwrites files because that is how the Unix rename() is defined and fs.rename() is documented as wrapping the rename() Unix syscall. I do not know of any place in the nodejs docs that directly states this regarding fs.rename(). However, there are a few things to note which let us determine this:

  1. The nodejs docs link to the Linux manpage for rename(2) when describing the functionality of fs.rename. The GitHub permalink of the docs does not linkify it, but the processer automatically turns rename(2) into rename(2).

  2. The “Syscalls and man pages” section of documentation states that syscalls emulate unix behavior on Windows. I infer this from the phrase “it’s sometimes impossible to replace Unix syscall semantics on Windows” which implies that nodejs has implemented Unix semantics on Windows when it is possible:

    Most Unix syscalls have Windows equivalents, but behavior may differ on Windows relative to Linux and macOS. For an example of the subtle ways in which it's sometimes impossible to replace Unix syscall semantics on Windows, see Node issue 4760.

  3. I’ve seen other discussions about things like this and people always refer to how nodejs just uses libuv for things so one should just look at libuv. libuv’s goal is to provide a portable asynchronous implementation of POSIX APIs and thus one of its goals is to behave like unix even on Windows. The libuv docs don’t seem to discuss rename() at length, but the Windows implementation of fs__rename() calls MoveFileEx() with MOVEFILE_REPLACE_EXISTING.

  4. Oh, and I almost forgot. Even if you know that nodejs defines fs.rename() as POSIX rename(), perhaps you don’t know the POSIX-defined behavior of rename() regarding overwriting:

    If the link named by the new argument exists, it shall be removed and old renamed to new. In this case, a link named new shall remain visible to other threads throughout the renaming operation and refer either to the file referred to by new or old before the operation began.

Simply, this describes a transactional file replacement if the target of the rename already exists. If a file with the new name already exists prior to calling rename(), it will never cease to exist—even if your program crashes or box loses power. At some point in time, the new name will start referring to the file with the old name.

You should prefer this method over removing the original file and then renaming the newly created one because then the file at the new path will cease to exist momentarily (possibly causing a race condition for something trying to open it) or, if the process is killed or a power failure happens at the right time, permanently.

Note: due to portability issues, it is good to consider using portability helpers like graceful-fs and cross-spawn when you want your code to also work for Windows users. I realize that is not the asker’s question, but I inferred that the asker would only ask such a question because of a win32 background where rename can’t overwrite files or because one would only ask a question such as this when interested in portability beyond Unix.


Short answer: yes


Long answer:

I created a script to check it:

var fs = require('fs');

Create two files:

fs.writeFileSync('a.txt',"This is a file")
fs.writeFileSync('b.txt',"This is another file")

Rename:

fs.renameSync('a.txt','b.txt');

Check if it was overriden:

var text = fs.readFileSync('b.txt', "utf-8");

console.log(text) // This is a file