console.log and friends
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.
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");Hello world 42 trueStrings print bare: textInside an array: [ 'text', 1, null, undefined ]{ name: 'Ada', born: 1815, tags: [ 'math', 'code' ] }
after a blank lineLook 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.
nullandundefinedprint 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.
const item = "tea";const price = 3.5;const qty = 4;
console.log(`${qty} x ${item} at ${price} each = ${qty * price}`);console.log(`Line oneLine two`);4 x tea at 3.5 each = 14Line oneLine twoThe 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.
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}`);Ada is 36 years oldAlan scored 87%Total: 10Total: 10The 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:
const people = [ { name: "Ada", born: 1815 }, { name: "Alan", born: 1912 },];
console.table(people);┌─────────┬────────┬──────┐│ (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:
process.stdout.write("loading");process.stdout.write("...");process.stdout.write("done\n");console.log("next line");loading...donenext lineThe "\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:
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:
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:
What is your name? AdaHello, 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.logand expecting a return value. It returnsundefined. 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: writeString(n)or a template literal. - Leaving out
closeInput(). The program hangs at the end, waiting for input. - Forgetting
awaitbeforeask. The program carries on without the answer, and you seePromise { <pending> }instead of the text.
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
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}.`);What is your name? AdaWhich year were you born? 1990Hello, Ada!In 2030 you will be 40.Number(...) converts the second answer so the subtraction works on numbers.
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
import { ask, closeInput } from "./prompt.mjs";
const width = Number(await ask("Width? "));const height = Number(await ask("Height? "));closeInput();
console.log(`Area: ${width * height}`);Width? 6Height? 7Area: 42Without 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.
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
process.stdout.write("1 ");process.stdout.write("2 ");process.stdout.write("3\n");1 2 3Each 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.logprints any number of values. Use template literals for exact text andconsole.tablefor lists of records.console.errorandconsole.warnwrite to stderr, andprocess.stdout.writewrites without a newline.- The copied
prompt.mjshelper andawait ask(...)read a line as a string. Convert it withNumber(...)if you need a number.