readline.clearLine()
Erases part or all of the current terminal line on a writable stream.
readline.clearLine(stream, dir[, callback])- Added in Node.js v0.7.7
Parameters
| Parameter | Type | Description |
|---|---|---|
$stream | stream.Writable | The TTY stream to write the escape sequence to, typically process.stdout. |
$dir | number | Which part of the line to erase: -1 to the left of the cursor, 1 to the right of the cursor, 0 the entire line. |
$callbackoptional | Function | Invoked 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
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.
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'.
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.
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