Back to results for “File System”
Node.js › File System (fs) Module

What is the difference between fs.rename() and manually copying then deleting a file, particularly across different filesystems or drives?

Intermediate

Answer

fs.rename() performs an atomic move operation when the source and destination are on the same filesystem -- the file appears to move instantly with no window where it exists in neither location, which is important for operations that must never leave a file in a half-moved, inconsistent state. However, rename() fails with an EXDEV error when moving across different filesystems or drives (common in some cloud/container storage setups), in which case a manual copy-then-delete sequence is required instead, which is not atomic and can leave the operation partially complete if it's interrupted midway.
const fs = require('node:fs/promises');

try {
  await fs.rename('/tmp/upload.tmp', '/data/final.txt'); // atomic, if same filesystem
} catch (err) {
  if (err.code === 'EXDEV') {
    await fs.copyFile('/tmp/upload.tmp', '/data/final.txt'); // fallback: not atomic
    await fs.unlink('/tmp/upload.tmp');
  } else {
    throw err;
  }
}
Real-world example A file-upload service writes incoming uploads to a temporary file first, then uses fs.rename() to atomically move it into its final location only once the upload is fully complete and verified, ensuring no partially-written file ever appears in the location where other parts of the system expect to find fully-uploaded files.

Common follow-ups: Why does an atomic rename specifically prevent other processes from ever observing a partially written file?;What common deployment scenario (like a Docker volume spanning different underlying storage) triggers the EXDEV cross-filesystem error in practice?