Cross-platform inter-process data sharing using file descriptors and named pipes.
@asyncvoid/share-fd provides a unified API for sharing data between processes using platform-specific memory sharing mechanisms. Data is written to a file descriptor or named pipe that can be passed to child processes, allowing efficient zero-copy data transfer disguised as a file path.
- Linux/FreeBSD/NetBSD:
memfd_create(anonymous memory-backed file descriptors) - macOS/Unix:
shm_open(POSIX shared memory) - Windows: Named Pipes
The share() function automatically selects the optimal method for your platform.
npm install @asyncvoid/share-fd
# or
yarn add @asyncvoid/share-fdimport { share } from '@asyncvoid/share-fd'
import { spawnSync } from 'node:child_process'
// Create a pipe with your data
const payload = Buffer.from('hello world')
const pipe = share(payload)
// Pass the file descriptor to a child process
const child = spawnSync(process.execPath, ['./child.js'], {
env: { ...process.env, CONFIG_PATH: '/proc/self/fd/3' },
stdio: ['ignore', 'pipe', 'ignore', pipe.fd],
encoding: 'utf8',
})
console.log(child.stdout) // "hello world"
// Clean up when done
pipe.close()import fs from 'node:fs'
// Read from the file descriptor passed via environment variable
const data = fs.readFileSync(process.env.CONFIG_PATH, 'utf-8')
console.log(data)You can also use platform-specific functions directly:
import { shareMemFD, shareSHM, shareNamedPipe } from '@asyncvoid/share-fd'
// Linux/FreeBSD only - memfd_create
if (process.platform === 'linux') {
const pipe = shareMemFD(Buffer.from('data'))
console.log(pipe.fd, pipe.name)
pipe.close()
}
// Unix/macOS - shm_open
if (process.platform === 'darwin') {
const pipe = shareSHM(Buffer.from('data'))
console.log(pipe.fd, pipe.name)
pipe.close()
}
// Windows - Named Pipes
if (process.platform === 'win32') {
const pipe = shareNamedPipe(Buffer.from('data'))
console.log(pipe.path)
pipe.close()
}Creates a platform-appropriate shared memory region with the given payload. Automatically selects:
memfd_createon Linux/FreeBSD/NetBSDshm_openon macOS and other Unix systems- Named Pipes on Windows
Parameters:
payload: Buffer containing the data to sharename(optional): Name hint for the shared resource
Returns: Pipe object with platform-specific properties
Linux/FreeBSD/NetBSD only. Creates an anonymous memory-backed file descriptor using memfd_create.
Unix/macOS. Creates a POSIX shared memory object using shm_open.
Windows only. Creates a named pipe for inter-process communication.
Unix/Linux (shareMemFD, shareSHM):
fd: number- File descriptor that can be passed to child processesname: string- Name of the shared resourceclose(): void- Closes the file descriptor
Windows (shareNamedPipe):
path: string- Named pipe path (e.g.,\\.\pipe\share-<ulid>)close(): void- Signals the pipe to stop accepting connections
import { memfd_create, shm_open, set_cloexec } from '@asyncvoid/share-fd'
// Create a memfd (Linux only)
const fd = memfd_create('myname', 0)
// Create shared memory (Unix)
const fd = shm_open('myshm', O_CREAT | O_RDWR, 0o600)
// Control close-on-exec flag (Unix)
set_cloexec(fd, true)- Rust (latest stable)
- Node.js 12.22.0+ / 14.17.0+ / 15.12.0+ / 16.0.0+
- yarn 1.x
yarn install
yarn buildThis will generate platform-specific native binaries (.node files).
yarn testRuns the test suite using ava.
yarn benchRuns performance benchmarks comparing different sharing methods.
With GitHub Actions, each commit and pull request is automatically built and tested across:
- Node versions: 20, 22
- Platforms: Linux (x64, ARM64), macOS (x64, ARM64), Windows (x64, ARM64)
- Variants: GNU libc, musl libc
Pre-built binaries are published as platform-specific optional dependencies, ensuring users don't need a Rust toolchain installed.
This package leverages platform-specific APIs to create memory regions that can be accessed as file paths:
- Data is written to a file descriptor or named pipe
- The descriptor is passed to a child process via
stdioarray - Child process reads from the descriptor using standard file I/O
- No disk I/O occurs - data stays in memory
This is particularly useful for:
- Passing configuration to child processes
- Sharing large data structures without serialization overhead
- Avoiding command-line argument length limits
- Secure data transfer (no temporary files on disk)
MIT