console.log and friends

Beginner30 min

Print values, format output with template literals, write without a newline, and read a line of input from the keyboard.

What you will learn
  • Print several values and objects with console.log
  • Build output text with template literals and format placeholders
  • Show tabular data with console.table and write without a newline using process.stdout.write
  • Read a line typed by the user with node:readline/promises
On this page

Output is how a program talks back to you, and console.log is the tool you will use most for debugging as well. This lesson covers the output tools Node.js gives you and the one way to read input that you need before the course gets to files and networks.

console.log

console.log takes any number of values, writes them separated by a space, and ends the line.

log_basics.mjs
console.log("Hello", "world", 42, true);
console.log("Strings print bare:", "text");
console.log("Inside an array:", ["text", 1, null, undefined]);
console.log({ name: "Ada", born: 1815, tags: ["math", "code"] });
console.log();
console.log("after a blank line");
Output
Hello world 42 true
Strings print bare: text
Inside an array: [ 'text', 1, null, undefined ]
{ name: 'Ada', born: 1815, tags: [ 'math', 'code' ] }
after a blank line

Look at how each kind of value is shown:

  • A string argument on its own prints without quotes. Inside an array or object, strings get single quotes so you can see where they start and end.
  • Arrays and objects print in a readable form on one line. Longer ones wrap to several lines automatically.
  • null and undefined print as their names.
  • console.log() with no arguments prints an empty line.
  • [ ... ] is an array, a list of values, and { ... } is an object, a record with named parts. Both get their own lessons later in this level. Here you only need to read their output.

This format is for the developer, not for the end user. If you need a precise format, build the text yourself.

Building text: template literals

A template literal is a string between backticks. Anything inside ${ } is evaluated, and its result is put into the text.

template_output.mjs
const item = "tea";
const price = 3.5;
const qty = 4;
console.log(`${qty} x ${item} at ${price} each = ${qty * price}`);
console.log(`Line one
Line two`);
Output
4 x tea at 3.5 each = 14
Line one
Line two

The expression qty * price is calculated inside the ${ }. Template literals can also span several lines, as in the second console.log: the line break in the source becomes a line break in the string. The strings lesson in the next module covers them in more detail.

Format placeholders

If the first argument of console.log is a string with placeholders, the following arguments fill them in. %s inserts text, %d a number, %i an integer (dropping the fraction), and %% prints a literal percent sign.

log_format.mjs
console.log("%s is %d years old", "Ada", 36);
console.log("%s scored %i%%", "Alan", 87.9);
console.log("Total:", 4 * 2.5);
console.log(`Total: ${4 * 2.5}`);
Output
Ada is 36 years old
Alan scored 87%
Total: 10
Total: 10

The last two lines print the same thing. Template literals are usually easier to read, so use placeholders only when you like their style or want console’s own formatting.

Other console methods

Method Does
console.error(...) Writes to stderr, like log otherwise
console.warn(...) Also writes to stderr
console.info(...) Same as log
console.table(data) Draws a table from an array of objects

console.table is a quick way to see a list of records:

table_demo.mjs
const people = [
{ name: "Ada", born: 1815 },
{ name: "Alan", born: 1912 },
];
console.table(people);
Output
┌─────────┬────────┬──────┐
│ (index) │ name │ born │
├─────────┼────────┼──────┤
│ 0 │ 'Ada' │ 1815 │
│ 1 │ 'Alan' │ 1912 │
└─────────┴────────┴──────┘

The (index) column is the position in the array. The columns after it come from the property names.

Writing without a newline

console.log always ends the line. To print pieces on the same line, use process.stdout.write, which writes exactly the text you give it:

write_no_newline.mjs
process.stdout.write("loading");
process.stdout.write("...");
process.stdout.write("done\n");
console.log("next line");
Output
loading...done
next line

The "\n" in the third call is an escape sequence that stands for a line break. process.stdout.write accepts a string (or raw bytes). A number throws an error, so convert numbers first.

Reading a line of input

Reading from the keyboard in Node.js takes machinery that this course has not taught yet. So you get a small helper to copy once. Save it as prompt.mjs, in the same folder as your programs:

prompt.mjs
import { createInterface } from "node:readline";
const reader = createInterface({ input: process.stdin });
const lines = reader[Symbol.asyncIterator]();
export async function ask(question) {
process.stdout.write(question);
const { value } = await lines.next();
return value ?? "";
}
export function closeInput() {
reader.close();
}

You do not need to follow it line by line. It prints a question, waits for the user to press Enter, and hands back what they typed as text. The export keyword makes ask and closeInput available to other files, which the lesson on ES modules explains. async is explained in the asynchronous module of the intermediate level.

Now a program can use the helper. Save this as greeting.mjs:

greeting.mjs
import { ask, closeInput } from "./prompt.mjs";
const name = await ask("What is your name? ");
closeInput();
console.log(`Hello, ${name}!`);
console.log(`Your name has ${name.length} letters.`);

Run it with node greeting.mjs. The terminal shows your own typing. If you type Ada:

Terminal window
What is your name? Ada
Hello, Ada!
Your name has 3 letters.

The import line loads the two helpers. await in front of ask(...) makes the program wait for the answer before the next line runs. It is allowed at the top of a .mjs file, and you only need to remember to write it before every ask.

Call closeInput() when you have asked everything. Without it, Node.js keeps waiting for more input and the program never ends.

Common pitfalls

  • Calling console.log and expecting a return value. It returns undefined. You get the printed text, not a value to use.
  • Forgetting backticks. "Total: ${x}" with ordinary quotes prints the characters ${x} literally.
  • Passing a number to process.stdout.write. It needs a string: write String(n) or a template literal.
  • Leaving out closeInput(). The program hangs at the end, waiting for input.
  • Forgetting await before ask. The program carries on without the answer, and you see Promise { <pending> } instead of the text.
ExerciseA greeting that asks for a name and a year

Using prompt.mjs, write a program that asks for a name and a birth year, then prints Hello, NAME! and In 2030 you will be AGE., where AGE is 2030 minus the year.

Input: Ada, then 1990. Expected output: Hello, Ada! and In 2030 you will be 40.

Show solution
greeting_year.mjs
import { ask, closeInput } from "./prompt.mjs";
const name = await ask("What is your name? ");
const year = Number(await ask("Which year were you born? "));
closeInput();
console.log(`Hello, ${name}!`);
console.log(`In 2030 you will be ${2030 - year}.`);
Terminal window
What is your name? Ada
Which year were you born? 1990
Hello, Ada!
In 2030 you will be 40.

Number(...) converts the second answer so the subtraction works on numbers.

ExerciseArea from two answers

Ask for a width and a height, then print Area: followed by their product. Convert both answers with Number(...).

Input: 6, then 7. Expected output: Area: 42.

Show solution
rect_input.mjs
import { ask, closeInput } from "./prompt.mjs";
const width = Number(await ask("Width? "));
const height = Number(await ask("Height? "));
closeInput();
console.log(`Area: ${width * height}`);
Terminal window
Width? 6
Height? 7
Area: 42

Without the two Number(...) calls the program would still print 42, because * converts text itself. With + it would join the digits instead, so converting at the point of input is the safe habit.

ExerciseNumbers on one line

Print the numbers 1 to 3 on one line separated by spaces, using only process.stdout.write, and end the line with a newline.

Input: none. Expected output: 1 2 3.

Show solution
write_numbers.mjs
process.stdout.write("1 ");
process.stdout.write("2 ");
process.stdout.write("3\n");
Output
1 2 3

Each call writes one number as text, and the last call adds the newline. A loop would do this better, and you will write one in a later module.

Summary

  • console.log prints any number of values. Use template literals for exact text and console.table for lists of records.
  • console.error and console.warn write to stderr, and process.stdout.write writes without a newline.
  • The copied prompt.mjs helper and await ask(...) read a line as a string. Convert it with Number(...) if you need a number.

Next: syntax, semicolons, comments and strict mode.