mrkeyoor.com_
Wed 23 Sept 00:36 UTC
npmUtilsupdated 22 Sept 2026

promise-breaker review

promise-breaker 7.0.0 adapts one function so callers can use either a Node-style error-first callback or a Promise. `promisify` starts from callback code, `callbackify` starts from Promise code, and `call` or `apply` invoke a plugin whose completion style is unknown. The current major is an ESM package and keeps lower-level `addPromise` and `addCallback` helpers for signatures that automatic callback detection cannot read safely. Our install loaded through both ESM import and CommonJS require, but it contained no TypeScript declarations despite the repository's TypeScript-oriented examples.

Verdict

Our promise-breaker 7.0.0 install took 0.8 seconds and bundled to 0.7 KB gzipped, but it shipped no TypeScript declarations and dual completion still needs two-path tests. Add it for a real callback compatibility promise; codebases that control their callers should expose async functions directly.

We installed it

Lab card: what happened when we installed promise-breakerScreenshot of promise-breaker documentation
Install✓ · 0.8s1 package on disk · 1 MB
ImportESM import works · require() works · ESM package
Browser0.7 KBgzipped (1.5 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does promise-breaker install cleanly?

Yes. In a fresh container with an empty cache, npm install promise-breaker finished in 0.8s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does promise-breaker add to a browser bundle?

0.7 KB gzipped (1.5 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does promise-breaker work with both ESM and CommonJS?

Yes. Both import 'promise-breaker' and require('promise-breaker') worked in Node 22 in our run. The package is published as ESM.

Does promise-breaker include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

promise-breaker or pify: which should you use?

pify: Use it when conversion only runs from callback functions toward Promise-returning functions. Our promise-breaker 7.0.0 install took 0.8 seconds and bundled to 0.7 KB gzipped, but it shipped no TypeScript declarations and dual completion still needs two-path tests.

When should you not use promise-breaker?

You own every caller and can choose async functions; a dual completion contract adds branches with no compatibility payoff

API stability3/5The current API is small and its jobs are clearly separated among `promisify`, `callbackify`, `call`, `apply`, `addPromise`, and `addCallback`. Version 7.0.0 is a major rewrite that renamed the main concepts, removed older option behavior, stopped preserving generated function length, and changed packaging to ESM. Compatibility aliases reduce some source edits, but the callback-position rules and packaging shift mean a version 6 application needs runtime tests rather than a blind dependency bump.
Docs4/5The README explains the library-author use case, shows both implementation directions, and documents all current helpers. It also discloses unusually important behavior: `promisify` creates a never-settling Promise for callback calls, `callbackify` can misread a trailing function argument, and lower-level helpers exist for manual control. The missing pieces are a concise v6-to-v7 migration page, a stated Node support floor, clearer double-completion guidance, and an explanation for the absence of declarations in the published package.
Maintenance4/5GitHub shows a push on 2026-06-08, the repository is unarchived, and there is 1 open issue or pull request. Version 7.0.0 was published with substantive implementation and packaging changes rather than a metadata-only release. The project has current automated tooling in the repository, but a new major with 85 stars has a smaller field of real-world migration reports than high-volume core utilities. The package's missing declarations also leave one release-quality question for typed consumers.
Ecosystem3/5The npm downloads endpoint counted 3,318,710 downloads in the latest completed week, and GitHub reports 85 stars. That reach reflects a long-standing Node compatibility problem, while modern Promise-first application code needs the package less often. It has no dependencies and works through ESM and CommonJS in our Node 22 check. Node's `util.promisify` and `util.callbackify`, plus packages such as universalify, cover adjacent one-way or dual-mode cases.

Use it if

  • A published library must preserve callback callers while adding Promise calls
  • A legacy codebase will migrate function by function instead of changing every caller together
  • A plugin hook may return a Promise or call a Node-style callback, and the host has to accept both
  • An unusual signature needs explicit `addPromise` or `addCallback` control rather than handwritten adapter boilerplate
Skip it if

Setup reality

Our install of promise-breaker 7.0.0 finished in 0.8 seconds. It left 1 package using 1 MB on disk; the package itself was 64 KB unpacked with 0 direct dependencies and 0 peer dependencies. npm audit reported 0 known vulnerabilities. Package metadata marks it as ESM and provides no exports map, yet both ESM import and CommonJS require() worked in our Node 22 sandbox. No TypeScript declarations were found. The browser result was 1.5 KB minified and 0.7 KB gzipped.

promisify always appends an internal callback. When the caller already supplies a callback at the implementation's expected position, that caller callback handles completion and the extra callback is ignored. The wrapper still creates a Promise in that branch, and the README warns that it never settles. Callback callers must ignore the return value; do not feed it into Promise tracking or request-lifecycle code.

callbackify treats the last function argument as the optional completion callback. If the wrapped function's real last argument is a mapper, predicate, or handler, pass { args: N } so it keeps that function. call and apply also append callbacks while observing a returned thenable. A plugin that uses both paths may complete twice, and the package does not add a timeout when neither path completes.

Version 7 has no documented Node engine floor and our package check found no declaration file, so test the exact runtime and add local types if needed. Synchronous exceptions, method this binding, callback errors, Promise rejections, and variadic signatures all deserve paired tests in both calling styles. New application code should usually expose one async contract and avoid this ambiguity.

Patterns

Await an error-first callback function promisify-callback

import { promisify } from 'promise-breaker';

const readUser = promisify((id, done) => {
  database.get(id, done);
});
const user = await readUser('42');

The implementation callback must use `(error, result)`. Several success arguments are outside this wrapper's documented shape.

Call the same wrapper with a callback keep-callback-caller

readUser('42', (error, user) => {
  if (error) return console.error(error);
  console.log(user);
});

Ignore the return value. In callback form, `promisify` creates an internal Promise that the README says never settles.

Add callbacks to async code callbackify-promise

import { callbackify } from 'promise-breaker';

const loadConfig = callbackify(async (file) => {
  const text = await fs.promises.readFile(file, 'utf8');
  return JSON.parse(text);
});
const config = await loadConfig('config.json');

Without a callback, the wrapper returns the implementation's Promise; callback calls receive an error-first result.

Preserve a trailing mapper function protect-function-argument

const mapAsync = callbackify({ args: 2 }, async (items, mapper) => {
  return Promise.all(items.map(mapper));
});
const doubled = await mapAsync([1, 2], (n) => n * 2);

The `args: 2` option stops `callbackify` from treating `mapper` as the completion callback.

Invoke a callback-or-Promise plugin call-unknown-style

import { call } from 'promise-breaker';

async function runPlugin(plugin, input) {
  return call(plugin.transform, plugin, input);
}
const output = await runPlugin(plugin, source);

Pass the owner as `thisArg`. No timeout is created if the plugin returns no thenable and never calls its callback.

Invoke unknown-style code with an array apply-arguments

import { apply } from 'promise-breaker';

const args = ['report.csv', { encoding: 'utf8' }];
const result = await apply(loader, loaderContext, args);

`apply` appends a callback to this array. Reject plugins that also return a Promise after calling that callback.

Place a callback explicitly with addPromise control-promise-wrapper

import { addPromise } from 'promise-breaker';

function lookup(id, options, done) {
  return addPromise(done, (finish) => {
    legacyLookup(id, options, finish);
  });
}

Use the lower-level helper when automatic trailing-callback placement is unsafe for the real signature.

Wrap async work with addCallback control-callback-wrapper

import { addCallback } from 'promise-breaker';

function calculate(input, done) {
  return addCallback(done, async () => {
    const value = await expensiveStep(input);
    return value * 2;
  });
}

When `done` exists, `addCallback` reports fulfillment or rejection through it and returns undefined.

Alternatives

PackageRegistryPick it when
pifynpmUse it when conversion only runs from callback functions toward Promise-returning functions.
universalifynpmUse it for focused fromCallback and fromPromise wrappers with a similar dual calling convention.
thenifynpmUse it when promisifying Node callbacks, including callbacks that return several success values.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.