This is a little-known way to console log without newline that many developers have never used.
Let’s say we need to log in a loop like this:
for (let i = 1; i <= 5; i++) {
// print number without newline
}
// Output: 1 2 3 4 5
❌ Unfortunately the normal way fails us:
So what do we do?

What we do: is process.stdout.write:
for (let i = 1; i <= 5; i++) {
process.stdout.write(`${i} `);
}
// Output: 1 2 3 4 5

How is process.stdout.write different from console.log?
Well first of all, console.log IS process.stdout.write!
stdout is the fundamental way every CLI program logs output to the console.
That’s what it uses at its core:
Console.prototype.log = function() {
this._stdout.write(util.format.apply(this, arguments) + '\n');
};But this extra processing makes it so much better for formatting:
- I can easily inspect objects with
console.logwithoutJSON.stringify:

But process.stdout.write fails miserably — it only accepts strings and Buffers:

But there’s something incredible only process.stdout.write can do:
Data streaming:

process.stdout is actually, a stream.
Streams represent data flow in Node.
- Read streams — data coming from
- Write streams — data going into
- Duplex streams — both
Data’s flowing from the file read stream into the stdout stream.
It’s the same as this:
import fs from 'fs';
fs.createReadStream('codingbeautydev.txt').on(
'data',
(chunk) => {
process.stdout.write(chunk);
}
);But pipe is much more natural for stream-to-stream data flow:
Letting you create powerful transformation pipelines like this:
import fs from 'fs';
import { Transform } from 'stream';
// ✅ duplex stream
const uppercase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
fs.createReadStream('codingbeautydev.txt')
.pipe(uppercase)
.pipe(process.stdout);
process.stdin
process.stdin is the process.stdout‘s input counterpart — a readable stream for user input.
So see how with a single line I create a pipeline to reflect all my input to me:
process.stdin.pipe(process.stdout);
And when I insert the uppercase transformation into the pipeline:
import fs from 'fs';
import { Transform } from 'stream';
// ✅ duplex stream
const uppercase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
process.stdin.pipe(uppercase).pipe(process.stdout);
process.stderr
Here to complete the standard stream trio.
console.log→process.stdinconsole.error→process.stderr
Probably also defined this way in Node:
Console.prototype.error = function() {
this._stderr.write(util.format.apply(this, arguments) + '\n');
};console.log('A normal log message');
console.error('An error message');You can see the difference in the browser:

Although not much difference on Node:

These are 3 powerful streams that let you input, process, and output data creatively and intuitively.
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.
