chmod in Node.js

fs.chmodSync(path, 0o755)

fs.chmodSync(path, 0o755) sets a file’s mode to rwxr-xr-x, the same as chmod 755 in a shell. 0o755 is an octal literal: each digit is three bits, read 4, write 2, execute 1, for the owner, the group and everyone else.

import fs from 'node:fs';

fs.chmodSync('deploy.sh', 0o755);
console.log((fs.statSync('deploy.sh').mode & 0o777).toString(8));   // '755'

The tool below reads 755 the same way: owner rwx, group and others r-x.

755, ‘755’ and 0o755

fs.chmodSync('deploy.sh', 755);     // decimal 755 is 0o1363: --wxrw--wt
fs.chmodSync('deploy.sh', '755');   // a string is read as octal: 0o755, rwxr-xr-x
fs.chmodSync('deploy.sh', '0o755');
// TypeError [ERR_INVALID_ARG_VALUE]: The argument 'mode' must be a 32-bit unsigned integer or an octal string. Received '0o755'

The bare number is the classic bug, and Node accepts it without a word: decimal 755 is octal 1363, so the owner can’t read the file, the group can write it but not run it, and the sticky bit comes on. Type 1363 into the tool to see the same -wxrw--wt. The string form is handy when the mode comes from a config file or a command line, but only as plain digits: '0o755' and 'rwxr-xr-x' both throw.

With promises

import { chmod, stat } from 'node:fs/promises';

await chmod('deploy.sh', 0o750);
console.log(((await stat('deploy.sh')).mode & 0o777).toString(8));   // '750'

The callback form, fs.chmod(path, mode, callback), takes the same modes.

Reading a mode and changing one bit

stats.mode includes the file type: that 750 file reports 33256, which is 0o100750, so mask it with & 0o777 before printing. chmod replaces the whole mode, so to add one bit, the way chmod u+x does, start from the current mode:

fs.chmodSync('deploy.sh', fs.statSync('deploy.sh').mode | fs.constants.S_IXUSR);   // 644 becomes 744

fs.constants names the nine permission bits but not setuid, setgid or sticky; the docs warn that values above 0o777 may behave differently across platforms. fs.chmodSync(path, 0o4755) did set setuid on Linux and macOS.

Creating files with a mode

fs.writeFileSync('run.sh', data, { mode: 0o777 }) creates the file as 755 under the usual umask 022, which removes bits from any mode given at creation. Writing the same file again with { mode: 0o700 } leaves it at 755: the option applies only when the file is created, so call chmod for an existing one.

Windows

The Node docs say that on Windows only the write permission can be changed, and owner, group and others aren’t distinguished. 0o444 makes a file read-only and 0o666 makes it writable again; 0o755 and 0o644 mean the same thing there.

Try it in the chmod Calculator

755 rwxr-xr-x

WhoReadWriteExecute
Owner
Group
Others
Special bits
Command
chmod 755 file

Runs in your browser. Nothing you enter is sent anywhere.