mrkeyoor.com_
Wed 23 Sept 00:34 UTC
npmCLI & Toolingupdated 22 Sept 2026

readline-sync review

readline-sync 1.4.10 asks for terminal input and blocks the entire Node process until the user responds. Its CommonJS API includes line questions, masked secrets, one-key choices, yes/no confirmation, numbered menus, validated numbers, paths, and small command loops. Version 1.4.10 only adjusted internal use of Node constants, reformatted code, and clarified `keyInPause`; the prompt API did not change. Straight-line calls are convenient, but timers, sockets, promises, and every other task stop while input is pending. GitHub archived the repository in November 2022.

Verdict

readline-sync 1.4.10 installed in 0.7 seconds as a single 1 MB package with 0 audit findings, but our browser build failed and GitHub archived it in 2022. Keep it for tiny interactive scripts where stopping the process is harmless; use an async prompt library or core readline for maintained CLIs, servers, and automated execution.

We installed it

Lab card: what happened when we installed readline-syncScreenshot of readline-sync documentation
Install✓ · 0.7s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does readline-sync install cleanly?

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

Can readline-sync run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does readline-sync work with both ESM and CommonJS?

Yes. Both import 'readline-sync' and require('readline-sync') worked in Node 22 in our run. The package is published as CommonJS.

Does readline-sync include TypeScript types?

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

readline-sync or prompt-sync: which should you use?

prompt-sync: Use it when blocking input is mandatory and a smaller prompt surface is enough. readline-sync 1.4.10 installed in 0.7 seconds as a single 1 MB package with 0 audit findings, but our browser build failed and GitHub archived it in 2022.

When should you not use readline-sync?

The process serves requests, maintains sockets, runs timers, or displays a live progress indicator. Every prompt blocks all of that work until a human answers.

API stability5/5Version 1.4.10 has kept the same question, prompt, key input, selection, typed-input, and command-loop helpers since its July 2019 publication. The option vocabulary is similarly fixed, including `limit`, `defaultInput`, masking, history, and boolean coercion. Archival removes the chance of deliberate breaking changes, though it also means future Node and terminal compatibility problems cannot receive a package update.
Docs4/5The README documents each method and option with console transcripts, including the 1024-byte direct-read buffer, single-key limits, masking caveats, persistent defaults, history expansion, path input, command loops, and placeholders. It also explains that synchronous reading can invoke an external program and stop the process. The page is very long, and its automation guidance is limited compared with the detail devoted to interactive tricks.
Maintenance1/5npm published 1.4.10 on July 27, 2019. GitHub's last push and archive date are November 3, 2022, and the repository is now read-only with 0 open issues because new reports cannot be filed. The final documentation change points users toward Promise, `await`, and `async`. Continued weekly downloads do not change the absence of a path for terminal or future Node fixes.
Ecosystem3/5The latest completed week recorded 4,699,408 npm downloads, and the zero-dependency package still appears in teaching material, generators, and older CLIs. Separate DefinitelyTyped declarations exist, but our package check found no bundled types, no browser route, and no plugin interface. Current prompt tooling centers on Promise-based libraries such as Inquirer, enquirer, and prompts, so their extensions and testing patterns do not transfer directly.

Use it if

  • A short local script needs one or two prompts and has no useful concurrent work while a person types.
  • Teaching material benefits from straight-line input code more than it benefits from current async conventions.
  • An existing CLI already depends on helpers such as `keyInSelect`, `questionInt`, or `questionNewPassword`.
  • Single-key input or masked text is needed and the supported terminal behavior has been tested on every target platform.
Skip it if

Setup reality

We installed readline-sync 1.4.10 in 0.7 seconds in a fresh Node 22 Bookworm sandbox. It left 1 package and 1 MB on disk. The package has 0 direct dependencies, 0 peers, a 156 KB unpacked size, an MIT license, and a declared floor of Node 0.8. npm audit found 0 known vulnerabilities. CommonJS require() and ESM import both worked in our checks, while no TypeScript declarations were present.

There are no credentials, native addons, or config files. The unusual part is the synchronous terminal implementation. Node's normal readline API is asynchronous, so this package can invoke an external program and block while it obtains input; older runtimes have additional file-piping fallbacks. Our browser bundle failed, which is expected for code tied to a local TTY. Treat it as Node-only even when a bundler can resolve the CommonJS entry.

Automation needs an alternate path before the first prompt. Read flags, environment variables, or a config file first, then prompt only when stdin is interactive. A missing TTY can raise an error instead of choosing a default. Masked input is also platform dependent: the README says redirected input on some Windows environments may use * or an empty mask regardless of the requested character. Never log the returned secret.

Options are broad and sometimes change return types. trueValue and falseValue return booleans only on a match; other input stays a string unless limit rejects it. keyInSelect returns -1 for cancel. keyInYN treats any non-Y key as false, while keyInYNStrict waits for Y or N. Global defaults persist until process exit, and history remembers the previous answer. For maintained async prompts, prefer Inquirer, prompts, or Node's built-in readline/promises.

Patterns

Read one answer synchronously ask-line-question

const readlineSync = require('readline-sync');

const name = readlineSync.question('Name? ');
console.log(`Hello, ${name}`);

The process stops at `question()` until Enter is pressed. Timers and network callbacks cannot run during that wait.

Mask secret input hide-password

const password = readlineSync.question('Password: ', {
  hideEchoBack: true,
  mask: '*',
});

Version 1.4.10 may substitute `*` or an empty mask on some redirected Windows inputs. The returned password is plain text in memory.

Prefer an environment value outside a TTY guard-automation

function readEnvironment() {
  if (process.env.DEPLOY_ENV) return process.env.DEPLOY_ENV;
  if (!process.stdin.isTTY) throw new Error('DEPLOY_ENV is required');
  return readlineSync.question('Environment: ');
}

A CI job or container may have no interactive terminal. Fail with a clear missing-input error before readline-sync attempts a read.

Wait for an explicit Y or N confirm-strictly

const approved = readlineSync.keyInYNStrict('Publish this release?');
if (!approved) {
  console.log('Cancelled');
  process.exitCode = 1;
}

`keyInYNStrict` ignores unrelated keys until Y or N. Plain `keyInYN` returns false for any key other than Y.

Choose from a numbered menu select-menu-item

const targets = ['staging', 'production'];
const index = readlineSync.keyInSelect(targets, 'Deploy where?');
if (index === -1) return;
await deploy(targets[index]);

Cancel returns -1. Check it before indexing or the chosen target becomes `undefined`.

Restrict a line to known values validate-choice

const color = readlineSync.question('Signal color: ', {
  limit: ['green', 'yellow', 'red'],
  limitMessage: '$<lastInput> is not allowed.',
});

A failed `limit` match re-prompts indefinitely. `$<lastInput>` inserts the rejected input into the displayed message.

Loop until the input is an integer read-integer

const port = readlineSync.questionInt('Port: ', {
  limit: (value) => value >= 1 && value <= 65535,
  limitMessage: 'Use a port from 1 through 65535.',
});

The helper does not return invalid input or enforce an attempt limit. A user can keep the process blocked indefinitely.

Use a default for an empty reply accept-default

const branch = readlineSync.question('Branch [main]: ', {
  defaultInput: 'main',
});

`defaultInput` applies when the user presses Enter without text. Show the same value in the prompt so the choice is visible.

Return a boolean for a limited answer coerce-boolean

const telemetry = readlineSync.question('Telemetry? ', {
  trueValue: ['yes', 'y'],
  falseValue: ['no', 'n'],
  limit: ['yes', 'y', 'no', 'n'],
});

Without `limit`, an unmatched answer remains a string and the return type varies between string and boolean.

Require an existing file path ask-file-path

const configPath = readlineSync.questionPath('Config file: ', {
  isFile: true,
  exists: true,
});

`questionPath` may expose `cd` and `pwd` behavior when that option is enabled. Keep it disabled if changing the process directory is unexpected.

Set defaults for later prompts set-process-defaults

readlineSync.setDefaultOptions({
  prompt: '> ',
  keepWhitespace: false,
  history: false,
});

const command = readlineSync.prompt();

Defaults remain active for the entire process. A method-level option overrides one call without resetting the stored defaults.

Move a prompt to Node's async API replace-with-core-readline

import { createInterface } from 'node:readline/promises';

const rl = createInterface({ input: process.stdin, output: process.stdout });
try {
  const name = await rl.question('Name? ');
  console.log(`Hello, ${name}`);
} finally {
  rl.close();
}

Core readline keeps the event loop available while the user types and adds no package, but it does not include readline-sync's menus and validation helpers.

Alternatives

PackageRegistryPick it when
prompt-syncnpmUse it when blocking input is mandatory and a smaller prompt surface is enough.
inquirernpmUse it for maintained async prompts, choices, validation, and keyboard navigation.
enquirernpmUse it for varied interactive prompt types with a Promise-based API.
promptsnpmUse it for a compact async question flow that is easy to inject or override in tests.

More cli & tooling guides

chalk · commander · typescript · esbuild · yargs · click · 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.