readline.clearLine()

Erases part or all of the current terminal line on a writable stream.

Signature
readline.clearLine(stream, dir[, callback])
  • Added in Node.js v0.7.7

Parameters

ParameterTypeDescription
$streamstream.WritableThe TTY stream to write the escape sequence to, typically process.stdout.
$dirnumberWhich part of the line to erase: -1 to the left of the cursor, 1 to the right of the cursor, 0 the entire line.
$callbackoptionalFunctionInvoked once the write operation completes.

Return value

booleanfalse if the stream wants the caller to wait for the 'drain' event before writing more data; otherwise true.

Errors

Throws ERR_INVALID_ARG_TYPE if callback is provided and is not a function, or if stream is not a writable stream.

Changelog

  • PHP v18.0.0Passing an invalid callback now throws ERR_INVALID_ARG_TYPE instead of ERR_INVALID_CALLBACK.
  • PHP v12.7.0The stream's write() callback and return value are exposed.

clearLine() writes one of three CSI erase sequences: ESC[1K for dir -1, ESC[0K for 1, and ESC[2K for 0. It blanks characters on the current row and nothing else.

When to reach for it

  • Wiping the previous frame of a spinner or progress bar before writing the next one.
  • Removing a transient status message once a task finishes.
  • Trimming the tail of a line you are rewriting shorter than before.

What trips people up

Erasing does not move the cursor. After clearLine(stream, 0) the cursor sits exactly where it was, so a following write() starts mid-line and leaves a run of spaces. Always pair it with cursorTo(stream, 0) — and note the order matters only for readability, since neither call depends on the other's effect.

The sign convention catches people out: -1 clears to the left, 1 to the right, and 0 — which reads like "nothing" — clears the whole line.

Like cursorTo, this writes escape bytes to any stream. In CI, or when output is piped, guard on process.stdout.isTTY, otherwise your logs fill with control characters and a shorter new frame will not visually replace a longer old one anyway.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Erase the previous spinner frame before drawing the next one
  • Remove a 'connecting…' message once the connection succeeds
  • Redraw a percentage counter that shrinks from 100% to 9%
  • Clear a partially typed prompt line before printing an error

Frequently asked questions

How do I clear the current line in a Node.js terminal?

Call readline.clearLine(process.stdout, 0) to erase the whole row, then readline.cursorTo(process.stdout, 0) to move back to column 0 before writing replacement text. Without the cursorTo, the next write starts wherever the cursor happened to be.

What do the dir values -1, 0 and 1 mean in clearLine?

-1 clears from the cursor to the left, 1 clears from the cursor to the right, and 0 clears the entire line. The values map to the escape sequences ESC[1K, ESC[0K and ESC[2K respectively.

Why does clearLine leave stray characters in my log file?

clearLine writes ANSI escape bytes to any writable stream, and a file or pipe stores them verbatim instead of acting on them. Check process.stdout.isTTY and fall back to ordinary console.log lines when it is false.

More examples

A spinner that cleans up after itself

stop() clears the line before printing the final message, so no fragment of the spinner frame is left on screen. Skipping the clear would leave '| installing' followed by the summary text on the same row.

Example · javascript
import readline from 'node:readline';

function spinner(label) {
  if (!process.stdout.isTTY) {
    console.log(`${label}...`);
    return { stop: (msg) => console.log(msg) };
  }
  const frames = ['|', '/', '-', '\\'];
  let i = 0;
  const timer = setInterval(() => {
    readline.cursorTo(process.stdout, 0);
    readline.clearLine(process.stdout, 0);
    process.stdout.write(`${frames[i++ % frames.length]} ${label}`);
  }, 80);
  return {
    stop(msg) {
      clearInterval(timer);
      readline.cursorTo(process.stdout, 0);
      readline.clearLine(process.stdout, 0);
      console.log(msg);
    },
  };
}

const s = spinner('installing');
await new Promise((r) => setTimeout(r, 1500));
s.stop('installed 42 packages');

Why dir 0 alone is not enough

Both blocks erase the same characters, but only the second one repositions the cursor, so the shorter replacement text starts at column 0. This is the single most common cause of 'my progress bar prints with a huge indent'.

Example · javascript
const readline = require('node:readline');

process.stdout.write('Progress: 100% ................');

// Wrong: erases the row but the cursor is still at column 32.
readline.clearLine(process.stdout, 0);
process.stdout.write('Progress: 9%');
// -> 32 blank columns, then 'Progress: 9%'

process.stdout.write('\n');

// Right: rewind first, then erase, then write.
process.stdout.write('Progress: 100% ................');
readline.cursorTo(process.stdout, 0);
readline.clearLine(process.stdout, 0);
process.stdout.write('Progress: 9%\n');

Clearing only what follows the cursor

dir 1 erases from the cursor to the end of the row, leaving the text to its left untouched. Use it when only the tail of a status line changes and rewriting the whole line would flicker.

Example · javascript
const readline = require('node:readline');

process.stdout.write('branch: main   (dirty, 3 files)');

// Keep the 'branch: main' prefix, drop everything after column 13.
readline.cursorTo(process.stdout, 13);
readline.clearLine(process.stdout, 1);
process.stdout.write('   (clean)\n');

Discussion

  • Be the first to comment on this lesson.