diff --git a/doc/api/fs.md b/doc/api/fs.md
index 9cb84007b3b815..cb46e1d867168a 100644
--- a/doc/api/fs.md
+++ b/doc/api/fs.md
@@ -8706,12 +8706,14 @@ The following constants are meant for use with `fs.open()`.
O_SYNC |
Flag indicating that the file is opened for synchronized I/O with write
- operations waiting for file integrity. |
+ operations waiting for file integrity. On Windows, this maps to
+ FILE_FLAG_WRITE_THROUGH.
O_DSYNC |
Flag indicating that the file is opened for synchronized I/O with write
- operations waiting for data integrity. |
+ operations waiting for data integrity. On Windows, this maps to
+ FILE_FLAG_WRITE_THROUGH.
O_SYMLINK |
@@ -8721,7 +8723,7 @@ The following constants are meant for use with `fs.open()`.
O_DIRECT |
When set, an attempt will be made to minimize caching effects of file
- I/O. |
+ I/O. On Windows, this maps to FILE_FLAG_NO_BUFFERING.
O_NONBLOCK |
diff --git a/src/node_constants.cc b/src/node_constants.cc
index 8abf3fd8afe483..08372767d84628 100644
--- a/src/node_constants.cc
+++ b/src/node_constants.cc
@@ -1165,10 +1165,22 @@ NODE_DEFINE_CONSTANT(target, UV_FS_O_FILEMAP);
#ifdef O_SYNC
NODE_DEFINE_CONSTANT(target, O_SYNC);
+#elif UV_FS_O_SYNC != 0
+// Windows lacks the POSIX O_SYNC macro, but libuv maps UV_FS_O_SYNC to
+// FILE_FLAG_WRITE_THROUGH, so expose it under the portable name.
+#define O_SYNC UV_FS_O_SYNC
+ NODE_DEFINE_CONSTANT(target, O_SYNC);
+#undef O_SYNC
#endif
#ifdef O_DSYNC
NODE_DEFINE_CONSTANT(target, O_DSYNC);
+#elif UV_FS_O_DSYNC != 0
+// Windows lacks the POSIX O_DSYNC macro, but libuv maps UV_FS_O_DSYNC to
+// FILE_FLAG_WRITE_THROUGH, so expose it under the portable name.
+#define O_DSYNC UV_FS_O_DSYNC
+ NODE_DEFINE_CONSTANT(target, O_DSYNC);
+#undef O_DSYNC
#endif
@@ -1178,6 +1190,12 @@ NODE_DEFINE_CONSTANT(target, UV_FS_O_FILEMAP);
#ifdef O_DIRECT
NODE_DEFINE_CONSTANT(target, O_DIRECT);
+#elif UV_FS_O_DIRECT != 0
+// Windows lacks the POSIX O_DIRECT macro, but libuv maps UV_FS_O_DIRECT to
+// FILE_FLAG_NO_BUFFERING, so expose it under the portable name.
+#define O_DIRECT UV_FS_O_DIRECT
+ NODE_DEFINE_CONSTANT(target, O_DIRECT);
+#undef O_DIRECT
#endif
#ifdef O_NONBLOCK
diff --git a/test/parallel/test-fs-constants.js b/test/parallel/test-fs-constants.js
index cdecfe5591631a..8ba07a0de81b49 100644
--- a/test/parallel/test-fs-constants.js
+++ b/test/parallel/test-fs-constants.js
@@ -1,5 +1,5 @@
'use strict';
-require('../common');
+const common = require('../common');
const fs = require('fs');
const assert = require('assert');
@@ -7,6 +7,15 @@ const assert = require('assert');
assert.notStrictEqual(fs.constants.S_IRUSR, undefined);
assert.notStrictEqual(fs.constants.S_IWUSR, undefined);
+// O_SYNC, O_DSYNC and O_DIRECT have no POSIX macro on Windows, but libuv
+// honors them via FILE_FLAG_WRITE_THROUGH / FILE_FLAG_NO_BUFFERING, so they
+// are exposed under their portable names with libuv's flag values.
+if (common.isWindows) {
+ assert.strictEqual(fs.constants.O_SYNC, 0x08000000);
+ assert.strictEqual(fs.constants.O_DSYNC, 0x04000000);
+ assert.strictEqual(fs.constants.O_DIRECT, 0x02000000);
+}
+
// Check null prototype.
assert.strictEqual(Object.getPrototypeOf(fs.constants), null);