mutexify
mutexify is a lightweight JavaScript library providing a mutex lock mechanism, primarily designed for Node.js environments. It ensures exclusive access to critical sections of code, guaranteeing that requests are processed in the strict order they were made, thereby preventing common race conditions in asynchronous operations. The library offers two main APIs: a traditional callback-based approach for immediate execution and a modern Promise-based alternative for cleaner `async/await` syntax. Currently at version 1.4.0, the package has maintained this version for approximately four years, suggesting a stable but slow release cadence. Its key differentiator lies in its semantic simplicity and strict adherence to ordered access, making it a straightforward and focused choice for basic locking needs without the overhead of more complex concurrency primitives like read/write locks or advanced semaphore features found in other libraries.
Common errors
-
TypeError: mutexify is not a function
cause Attempting to `import mutexify from 'mutexify'` in a pure ESM environment where a bundler or Node.js's default interoperability cannot correctly resolve the CommonJS default export, resulting in `mutexify` being `undefined` or a malformed module object.fixIf using Node.js, ensure your `package.json` either has `"type": "commonjs"` (for the file containing the import) or use `const { default: mutexify } = await import('mutexify');` or `const mutexify = require('mutexify');` within an ESM module by creating a `require` function: `import { createRequire } from 'module'; const require = createRequire(import.meta.url); const mutexify = require('mutexify');` -
Application hangs indefinitely / Code stops executing after a mutex acquisition.
cause The `release()` function, obtained after acquiring a lock with the Promise-based API, was not called. This leaves the mutex in a permanently locked state, preventing any subsequent lock requests from resolving.fixReview the code paths within your critical section and ensure that `release()` is called on every exit point, especially in error handling. The most robust solution is to use a `try...finally` block to guarantee `release()` is invoked: `const release = await lock(); try { /* protected code */ } finally { release(); }`
Warnings
- gotcha Mutexify does not provide native ESM exports. It is a CommonJS module, which means direct `import` statements in pure ESM environments might require bundler configuration or Node.js's `createRequire` utility, though most modern setups handle CJS default imports automatically.
- gotcha It is critical to ensure that the `release()` function returned by the Promise-based API is always called, even if errors occur within the locked block. Forgetting to call `release()` will lead to a permanent deadlock, where subsequent lock requests will never resolve.
- gotcha The package has not been updated in approximately four years (as of 2026). While this indicates a stable API, it also means new features, performance optimizations, or critical bug fixes are unlikely to be released promptly. Consider its maintenance status for long-term project viability.
Install
-
npm install mutexify -
yarn add mutexify -
pnpm add mutexify
Imports
- mutexify
const mutexify = require('mutexify');import mutexify from 'mutexify';
- mutexifyPromise
const mutexifyPromise = require('mutexify/promise');import mutexifyPromise from 'mutexify/promise';
- Mutexify
import { Mutexify } from 'mutexify';import type { Mutexify } from 'mutexify';
Quickstart
import mutexify from 'mutexify/promise';
const lock = mutexify();
async function performLockedOperation(id) {
console.log(`[Op ${id}] Requesting lock...`);
const release = await lock();
try {
console.log(`[Op ${id}] Lock acquired. Performing work...`);
// Simulate some asynchronous work inside the locked section
await new Promise(resolve => setTimeout(resolve, Math.random() * 500 + 200));
console.log(`[Op ${id}] Work finished.`);
} finally {
release(); // Ensure the lock is always released
console.log(`[Op ${id}] Lock released.`);
}
}
(async () => {
console.log('Starting concurrent operations...');
// Schedule multiple operations concurrently to demonstrate mutex behavior
const operations = Array.from({ length: 5 }, (_, i) => performLockedOperation(i + 1));
await Promise.all(operations);
console.log('All operations completed.');
})();