Running JavaScript: Browser Console and Node.js
The places to run JavaScript while you learn: the browser console, a script tag in a web page, the Node.js REPL and script files, and printing output with console.log.
Four ways to run JavaScript
JavaScript always runs inside a runtime environment (see What Is JavaScript?). While you learn, you will use four entry points:
| Where | How | Good for |
|---|---|---|
| Browser console | Developer tools, Console tab | Trying one line; inspecting a live page |
| Script in a web page | <script> element in an HTML file |
Code that works with the page |
| Node.js REPL | node in a terminal |
Trying ideas without a browser |
| Node.js script | node file.js |
Real programs, tools and automation |
You need no installation for the first two: every desktop browser has a JavaScript engine and a console. For the last two, install the current Long-Term Support (LTS) version of Node.js (see Node.js versions). A code editor such as Visual Studio Code helps with all of them: it colors the syntax, completes names and marks errors as you type.
Installing Node.js
Check first whether Node.js is already there: open a terminal
(Terminal on macOS and Linux, Windows Terminal or PowerShell on
Windows) and type node --version. If the command is not
found, install the LTS version:
-
Windows and macOS: the installer from
nodejs.org/en/download
(choose the LTS version), or a package manager:
winget install OpenJS.NodeJS.LTSon Windows,brew install node@24with Homebrew on macOS. Plainbrew install nodegives the newest Current line, not the LTS. -
Linux: the distribution's own
nodejspackage is often an older release line, so check its version. The download page also lists other ways to get a current LTS, such as a version manager (nvm, fnm) that installs Node.js in your home folder and lets you switch between versions.
npm, the package manager for JavaScript, comes with Node.js; see
Modules and npm. Afterward,
node --version and npm --version both
print a version number.
The browser console
The browser console is the part of the browser developer tools where you can type JavaScript and see its result at once, and where the page's own scripts write their messages and errors. Open it with F12 and pick the Console tab, or go there directly with Ctrl+Shift+J in Chrome and Edge, Ctrl+Shift+K in Firefox (on macOS, Cmd+Option instead of Ctrl+Shift). In Safari, first enable the developer features in the settings.
The console is a REPL (read, evaluate, print, loop): it reads a
line, runs it and shows the value. You do not need
console.log() to see the value of an expression:
> 1250 * 0.21 262.5 > let region = "North" undefined > region.toUpperCase() 'NORTH' > document.title 'Outage map — Kestrel Energy'
The undefined after let region = … is not
an error. A declaration is a statement, not an expression, so it has
no value to show, and the console prints
undefined instead. The console runs in the context of
the page that is open, so document is that page: you
can read and change it live. Press Shift+Enter
for a new line without running the code yet.
The script element in a web page
A web page runs JavaScript with the
script element,
<script>. It can hold the code itself (an
inline script) or load it from a separate file with the
src attribute (an external script):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Outage map</title>
<!-- External script: downloaded now, run after the page is parsed -->
<script src="outages.js" defer></script>
</head>
<body>
<h1>Current outages</h1>
<p id="status">Loading…</p>
<!-- Inline script: runs as soon as the browser reaches it -->
<script>
console.log("Page parsed up to here");
</script>
</body>
</html>
Some rules that follow from how browsers read a page:
-
The browser reads HTML from top to bottom. A plain
<script>stops that reading until the script has been downloaded and run. A script that runs before an element exists cannot find it. -
Two common fixes: put scripts at the end of
<body>, or put them in<head>with thedeferattribute.deferdownloads the file in parallel and runs it after the whole page has been parsed, in the order the scripts appear. It works only for external scripts. -
type="module"loads the file as an ES module, which is deferred automatically and may useimport(see Modules and npm). -
An element with
srcmust be empty: code between the tags of an external script is ignored. - Prefer external files. They are cached by the browser, are easy to lint and test, and work with a strict Content Security Policy, which can forbid inline scripts.
How a script then reads and changes the page is the subject of The DOM and Events.
The Node.js REPL
Type node without a file name in a terminal and you get
the Node.js REPL, the same idea as the browser console but without a
web page. The prompt is >:
node
Welcome to Node.js v24.21.0. Type ".help" for more information. > const prices = [0.31, 0.29, 0.34] undefined > prices.length 3 > Math.max(...prices) 0.34 > _ * 100 34 > .exit
In the REPL, _ holds the last result,
.help lists the commands that start with a dot, and
.exit (or Ctrl+D, or
Ctrl+C twice) leaves it. Press
Tab to complete names: type Math. and press
Tab twice to see everything in Math.
Running a script file
For anything longer than a few lines, write a file. Save this as
outages.js:
// outages.js — count open outage tickets per region
const tickets = [
{ id: "INC-20417", region: "North", open: true },
{ id: "INC-20418", region: "South", open: false },
{ id: "INC-20421", region: "North", open: true },
];
let openNorth = 0;
for (const ticket of tickets) {
if (ticket.open && ticket.region === "North") {
openNorth++;
}
}
console.log("Open tickets in North:", openNorth);
Open tickets in North: 2
Then run it from a terminal. The terminal works in one folder at a
time, its
working directory, and node outages.js looks for the file there; so
first go to the folder where you saved it with
cd (pwd shows where you are). Otherwise
Node.js reports Error: Cannot find module with the full
path it tried.
cd ~/projects/js # the folder that contains outages.js
node outages.js
node --version # which Node.js is installed
node --watch outages.js # run again every time the file is saved
Node.js runs the file from top to bottom and exits when there is nothing left to do. If a line throws an error that nothing catches, Node.js stops there and prints the error with a stack trace: the file, line number and function calls that led to it. The page on error handling explains how to read one.
Executable scripts on Linux and macOS
A script can start with a shebang line, so you can run it
like any other command. JavaScript allows #! on the
very first line (standardized in ES2023):
#!/usr/bin/env node
console.log("Meter check complete");
chmod +x check-meters.js
./check-meters.js
Printing with console.log()
console.log() writes its arguments as one line of text to the console: the browser console in a web page, standard output in Node.js. Give it several arguments and it separates them with spaces. Call it without arguments for an empty line.
const customer = "Lucía Romero";
const kwh = 312.5;
const pricePerKwh = 0.31;
console.log("Invoice for", customer);
console.log("Usage:", kwh, "kWh");
console.log();
console.log("Amount due:", kwh * pricePerKwh);
console.log("Rounded:", (kwh * pricePerKwh).toFixed(2));
Invoice for Lucía Romero Usage: 312.5 kWh Amount due: 96.875 Rounded: 96.88
Logging values and objects
Text on its own is printed without quotes. Inside an array or an
object, Node.js shows how each value would be written in code, so
strings get single quotes. That lets you see the difference between
the number 5 and the string "5":
console.log(5, "5");
console.log([5, "5"]);
console.log({ meter: "KE-4471", readings: [118.2, 119.0], online: true });
console.log("Nested:", { site: { address: { geo: { lat: 52.01 } } } });
5 5
[ 5, '5' ]
{ meter: 'KE-4471', readings: [ 118.2, 119 ], online: true }
Nested: { site: { address: { geo: [Object] } } }
Notice 119: there is no separate integer type, so
119.0 and 119 are the same number. Node.js
shows objects nested more than two levels deep as
[Object]. A browser console shows objects as a tree you
can expand instead.
The first argument can contain placeholders: %s for a
string, %d for a whole number, %o for an
object. Template literals (see
Strings and Template Literals) are usually easier to read:
const region = "North";
const customers = 1250;
console.log("%s: %d customers without power", region, customers);
console.log(`${region}: ${customers} customers without power`);
North: 1250 customers without power North: 1250 customers without power
Other console methods
| Method | Use |
|---|---|
console.info() |
Same as console.log(); some consoles add an
icon
|
console.warn() |
A warning: yellow in the browser, standard error in Node.js |
console.error() |
An error message: red in the browser, standard error in Node.js |
console.table() |
An array of objects as a table (see Debugging and Developer Tools) |
In a terminal, console.log() and
console.error() look the same, but they go to different
streams: standard output and standard error. That matters when
output is redirected to a file or piped into another program; error
messages then stay visible (see
Pipes and Redirection). In the browser console you can filter the messages by level.
Statements, comments and semicolons
A JavaScript program is a series of statements. Curly
braces { } group statements into a block; indentation
is only for readers. Names are case-sensitive:
console works, Console does not:
console.log("Checking meters");
Console.log("Done");
Checking meters ReferenceError: Console is not defined
Comments come in two forms: // to the end of the line,
and /* … */ for a block that can span lines. A comment
that starts with /** is a documentation comment
(JSDoc), read by editors and tools.
Automatic semicolon insertion
Statements end with a semicolon. If you leave one out, the engine usually inserts it for you where a line break makes the statement complete. This automatic semicolon insertion is why code without semicolons mostly works — and why it sometimes does something you did not mean:
function statusText() {
return
"All meters online";
}
console.log(statusText());
undefined
A line break directly after return ends the statement,
so the function returns nothing and the string below is never
reached. Keep the value on the same line as return.
Whether a team writes semicolons or not is a style choice; a
formatter such as Prettier applies it consistently (see
Code Quality).
Strict mode
Early JavaScript was forgiving: many mistakes failed silently instead of raising an error. ES5 (2009) added strict mode, an opt-in variant of the language that turns several of those silent mistakes into errors and forbids a few confusing features. The most useful difference for beginners: assigning to a variable that was never declared. Without strict mode, a typo quietly creates a new global variable:
let totalKwh = 0;
totlKwh = 312.5; // typo: creates a new global variable
console.log(totalKwh);
0
The program runs and prints the wrong answer. With the directive
"use strict"; as the first statement of the file (or of
a function), the same typo stops the program at the line that is
wrong:
"use strict";
let totalKwh = 0;
totlKwh = 312.5; // typo
console.log(totalKwh);
ReferenceError: totlKwh is not defined
Strict mode also, among other things:
-
throws a
TypeErrorwhen you assign to a read-only property, instead of ignoring it; -
forbids two parameters with the same name and the old
withstatement; -
leaves
thisasundefinedin a plain function call instead of pointing to the global object (see Classes, Prototypes and this).
You rarely need to write the directive yourself in modern code:
ES modules and class bodies are always strict.
Plain scripts and Node.js CommonJS files (the default
.js files) are not, so add "use strict";
at the top of those.