completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Engines, runtimes & hosts

Learn how the JavaScript engine that runs the language differs from the browser, server runtime, or host APIs around it.

By the end, you'll know
  • 01
    The engine's jobName the V8, SpiderMonkey, and JavaScriptCore engines, and say what an engine does.
  • 02
    The host's jobTell the JavaScript language apart from the extra tools that browsers, Node.js, Deno, and Bun add.
  • 03
    One main threadSee why long synchronous work freezes a page, and how small slices keep it working.

The engine, the host, and the runtime

People say "JavaScript runs in Chrome." They also say "JavaScript runs in Node.js" and "JavaScript has document.querySelector." Each sentence talks about a different part. This lesson gives each part its name.

There are three words to learn:

  • A JavaScript engine is a program that reads your JavaScript code and runs it. It knows the rules of the language: variables, functions, arrays, Promise, and so on.
  • The host is the bigger program that the engine sits inside, such as a browser tab or Node.js. The host adds extra tools that reach the outside world, such as the web page or the files on your computer. These extra tools are called host APIs. An API is a set of names your code can use to ask another program to do something.
  • A runtime is a program you install to run JavaScript. It comes with an engine and the extra tools. Node.js, Deno, and Bun are runtimes. They run JavaScript outside a browser, for example on a server. A server is a computer that sends web pages and data to other computers.
A browser tab, which is the host. Inside it, an engine card that runs the JavaScript language. Beside the engine, three extras that the host adds: document, localStorage, and alert.browser tab = the hostengineruns thelanguagedocumentlocalStoragealertextras from the host
The engine runs your JavaScript. The browser tab around it is the host. The host adds extras that talk to the outside world, such as document for the page.
The short version

The engine runs JavaScript. The host gives JavaScript a place to run and extra tools to reach the outside world.

The next lesson, Manuals & specifications, shows where to look up the exact rules of the language and which browsers support a feature. For this lesson, you only need your browser.

V8, SpiderMonkey & JavaScriptCore

MAP IT

There is more than one JavaScript engine. Every engine does the same jobs:

  • It reads your code.
  • It checks that the code follows the grammar of JavaScript. This grammar is called syntax.
  • It creates the values and functions that your code describes.
  • It runs your statements and gives back the results.

Different companies build different engines. They all follow the same rule book for JavaScript, the ECMAScript standard from the previous lesson.

The table lists the three engines you'll hear about most. Read each row from left to right: the engine's name, the programs that use it, and who builds it.

Three common JavaScript engines and where you meet them
EngineWhich programs use it?Who builds it?
V8Chrome, Edge, Opera, Node.js, and Deno use it.Google builds V8.
SpiderMonkeyFirefox uses it.Mozilla builds SpiderMonkey.
JavaScriptCoreSafari and Bun use it.Apple builds JavaScriptCore.

An engine's name is not the name of a different language. All three engines run the same JavaScript. Most everyday code works the same in all of them, because they follow the same standard.

A browser is more than its engine. It also draws the page, handles clicks, and much more. So "Chrome" and "V8" are not two words for the same thing.

Plain math runs in every enginePop out in the code editor (opens in a new tab)JavaScript
const price = 3;
const quantity = 2;
console.log(price * quantity);

This code uses only numbers and *, the multiply sign. Both are part of the JavaScript language. So every modern engine can run it and print 6.

This does not mean every host has the same extra tools for pages, files, or the network. It only shows that the rules of the language come with every engine.

Name a browser and its enginePop out in the code editor (opens in a new tab)JavaScript
const browser = "Firefox";
const engine = "SpiderMonkey";
console.log(browser + " uses " + engine);

Line 1 stores the name Firefox. Line 2 stores the name of its engine, SpiderMonkey. Line 3 joins them into one sentence and prints Firefox uses SpiderMonkey. The two names are typed by hand. The code does not check which browser is running it.

Name a runtime and its enginePop out in the code editor (opens in a new tab)JavaScript
const runtime = "Node.js";
const engine = "V8";
console.log(runtime + " uses " + engine);

This is the same three-line pattern for a runtime. Line 1 stores Node.js, line 2 stores V8, and line 3 prints Node.js uses V8. Again, the names are typed by hand. The code does not check which program is running it.

Real-life analogyOne car engine, different car bodies

A car engine does not decide whether the car has two seats, a big trunk, or a roof rack. It only gives power. The rest of the car decides what the car can do. One engine can go into a van and into a truck. The engine is the same, but each car can do different things.

In real life: A car engine makes the car move
In JavaScript: A JavaScript engine makes your code run
In real life: The body can be a van, a sports car, or a truck
In JavaScript: The host can be Chrome, Safari, Node.js, Deno, or Bun
In real life: The same engine can go into several car models
In JavaScript: V8 sits inside Chrome and inside Node.js
Two windows. Chrome holds the V8 engine plus document. Node.js holds the same V8 engine plus process.ChromeV8+documentpage toolsNode.jsV8+processserver tools
Chrome and Node.js both use the V8 engine. Chrome adds page tools such as document. Node.js adds server tools such as process.

Engine names come up in a few places. You see them in release notes, which list the changes in a new version. They help when code works in one browser but not in another. And you hear them when someone says a runtime is "built on V8."

Engine names do not mean you write three versions of your code. For beginner code, almost everything works the same in every engine.

Browsers vs Node.js, Deno & Bun

INTERACTIVE

Each host adds its own extra tools:

  • A browser adds tools for the web page: window, document, localStorage, alert, and many more.
  • A runtime such as Node.js adds tools for servers. Your code can read files, read the words typed after the command that started the program, and read settings stored outside the program.

These are host APIs. The host gives you these names. The JavaScript language does not.

Check whether a page existsPop out in the code editor (opens in a new tab)JavaScript
const hasPage = typeof document !== "undefined";
console.log(hasPage ? "page available" : "no page");

typeof gives the type of a value as text, such as "object". Most code fails when it uses a name that does not exist. typeof does not fail. It gives "undefined" instead.

So line 1 is safe even when there is no document. In a browser page, this code prints page available. In Node.js, it prints no page. Check like this before you use a host API in code that can run in both places.

The clearest test is to ask the host which global names exist. A global name is one your code can use anywhere, without creating it first. Run this experiment in your browser and look at three results:

  • window and document exist here, because this is a browser.
  • process usually does not exist here. It belongs to Node.js.
  • globalThis exists in every modern host. It is the standard name for the object that holds all the global names.
Which host am I in?
Browser host probePop out in the code editor (opens in a new tab)JavaScript
const info = {  window: typeof window,  document: typeof document,  process: typeof process,  globalThis: typeof globalThis,  userAgent: navigator.userAgent,};console.table(info);
Real resultnot yet
typeof window
not checked yet
typeof document
not checked yet
typeof process
not checked yet
typeof globalThis
not checked yet

Engine guess: Click Run check to ask this browser.

User agent: waiting for the browser

Try it yourself

This code ran in your browser. It found window=not checked yet, document=not checked yet, process=not checked yet, globalThis=not checked yet.

The engine guess reads the browser's user agent text. Browsers can shorten that text or pretend to be another browser, so the guess is a clue, not proof.

Now pick one name and check it. The answer comes from the page you are reading, so another browser or Node.js may give a different answer. The in operator checks whether an object has a property with a given name. Here it checks globalThis.

Check one name in this host
Check one globalPop out in the code editor (opens in a new tab)JavaScript
const name = "document";console.log(name in globalThis);
Current pagedocument

checking…

Try it yourself

Checking whether this host has document…

This checks only the page you are reading, not every browser or runtime. The menu changes only the name being checked.

The engine guess reads navigator.userAgent. This is a line of text the browser gives about itself. It is only a clue, not proof. Browsers can shorten this text, stop updating it, or pretend to be another browser.

So don't trust the exact text. Remember the main idea instead: the same language runs inside different hosts.

You can also step through the checks one at a time. This replay asks whether the current host has document and whether it has Node's process. Compare the answers with the live values above.

Check two global names in this host
Step 0 of 3Ready
Your turn: follow the blue line

This replays two real checks in the host you are using now. It is not a view inside the engine.

Running in
  1. script
Next: line 1
const hasProcess = "process" in globalThis;console.log(hasDocument + " " + hasProcess);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Node.js, Deno, and Bun

Node.js, Deno, and Bun are runtimes. You install one on your computer to run JavaScript outside a browser. Node.js and Deno use the V8 engine. Bun uses JavaScriptCore. Each one adds its own command-line tools and host APIs.

Language features vs host APIs

SORT IT

When someone says code "works in JavaScript," ask a more exact question: is this part of the language, or did the host add it?

  • Language features come with every engine, so they work in every host.
  • Host APIs depend on where the code runs.
A built-in array methodPop out in the code editor (opens in a new tab)JavaScript
const cart = ["tea"];
const labels = cart.map((item) => item.toUpperCase());
console.log(labels[0]);

Line 1 makes a cart array with one item, "tea". Line 2 uses map, an array method from the language. It makes a new array with each item in capital letters. Line 3 prints TEA.

This code works in a browser and in Node.js. A page tool such as document does not.

Read saved cart dataPop out in the code editor (opens in a new tab)JavaScript
const savedCart = '{"item":"tea","quantity":2}';
const cart = JSON.parse(savedCart);
console.log(cart.quantity);

This is another language feature. Line 1 holds text that could come from saved data or from a server. On line 2, JSON.parse turns that text into a JavaScript object. So line 3 prints 2. The code needs only a string. It does not need a browser page.

Language feature or host API?
  • Array.prototype.map
  • JSON.parse
  • Math.max
  • Promise
  • document.querySelector
  • localStorage
  • fetch
  • alert
  • process.argv
  • require('fs')
  • setTimeout
  • console.log
Try it yourself
0 of 12 correct

Sort each name by who gives it to you. Read the explanation after each card. Some answers are close on purpose.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Use this table when a name works in one place but not in another. Find what you see in the first column. Then ask the question in the second column.

Which question to ask about a name
What do you see?What should you ask?Examples
Syntax, or a built-in object such as Array or JSON.Does this engine support this language feature?Array.prototype.map, JSON.parse, Promise
A tool for the page, storage, pop-ups, or the network.Does this host give me that API?document, localStorage, alert, fetch
A tool for files, command-line words, or packages.Which runtime is this code written for?process.argv, require('fs')
A name that works in many places.Do several hosts each give me this API?console, setTimeout, and often fetch

Knowing the difference saves you from a common mix-up:

  • Array.prototype.map works in Node.js and in a browser, because arrays are part of the language.
  • document.querySelector finds an element on the page. It works in a browser, because the browser gives you a page. In plain Node.js there is no page, so it fails.
  • fetch asks a server for data over the network. It is a host API, and browsers and most runtimes give it to you. When its details matter, check the runtime's documentation.
Left: cart.map works in a browser and works in Node.js. Right: document.title works in a browser but gives an error in Node.js.cart.map(...)browserworksNode.jsworkslanguage: works everywheredocument.titlebrowserworksNode.jserrorbrowser extra: page only
map is part of the JavaScript language, so it works in every host. document is an extra from the browser. Node.js has no page, so it gives an error.
Skip the page update when there is no pagePop out in the code editor (opens in a new tab)JavaScript
function showGreeting(page, user) {
  if (!page) return "No page to update";
  page.textContent = "Hi, " + user;
  return page.textContent;
}
console.log(showGreeting(null, "Asha"));

showGreeting takes a page element and a user's name. Line 2 checks the element. If there is none, the function returns "No page to update" and stops.

Line 6 passes null, which means "nothing here." So the code prints No page to update. In a browser, you could pass an element from document.querySelector instead. The page work sits in one small spot, so the function works in any host without an error.

The next replay steps through a script that calls one function. Pick a host name for line 1. Then predict what line 7 prints.

One script, one function call
Step 0 of 8Ready
Your turn: follow the blue line

Predict the sentence that line 7 prints. Then step through how the script calls one function and comes back.

Running in
  1. script
Next: line 1
function describeHost(place) {  const kitchen = place + " host";  return "JavaScript running in a " + kitchen;}const summary = describeHost(host);console.log(summary);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 1, then predict line 7

The steps happen in the same order either way. Only the value passed into the function changes.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

One main thread at a time

REAL FREEZE

A thread is one line of work that a computer does, one step after another. The browser runs ordinary page code on its main thread. The main thread also updates what you see on the page. It does one job at a time.

When code calls a function, the code around it pauses. The function runs and returns. Then the next statement runs. Code that runs straight through like this, one statement after another, is called synchronous code.

Real-life analogyOne cashier, one line

Picture one cashier in a small shop. A customer with a huge order makes everyone else wait. If the cashier rings up that order in small parts and serves quick customers in between, the line keeps moving.

In real life: One cashier serves one customer at a time
In JavaScript: The main thread runs one JavaScript task at a time
In real life: A huge order makes everyone behind it wait
In JavaScript: A long loop makes clicks and page updates wait
In real life: The cashier rings up the huge order in parts and serves others in between
In JavaScript: Timers split the work into slices, and the host gets a turn between slices

Try the demo. The counter goes up each time the browser redraws the page. The first button runs a busy loop for about 1.5 seconds. While the loop runs, the counter stops and clicks do nothing.

The second button does about the same amount of work in small slices. It uses setTimeout, which asks the host to run a function a little later. Between slices, the browser gets a chance to redraw the page.

Main thread freeze test
Main-thread demoPop out in the code editor (opens in a new tab)JavaScript
let frame = 0;function tick() {  frame = frame + 1;  requestAnimationFrame(tick);} function blockFor(milliseconds) {  const end = performance.now() + milliseconds;  while (performance.now() < end) {    // Busy work keeps the main thread occupied.  }} function chunkedWork(milliseconds) {  const end = performance.now() + milliseconds;  function slice() {    const sliceEnd = Math.min(performance.now() + 25, end);    while (performance.now() < sliceEnd) {}    if (performance.now() < end) setTimeout(slice, 0);  }  slice();}
Moving counteridle
0

Try clicking another button while the busy loop runs. The click waits until the loop ends.

Try it yourself

The counter goes up each time the page redraws. Try the busy-loop button, then the slices button.

Both buttons do about the same amount of busy work. The first keeps the main thread busy the whole time. The second stops after each slice, and setTimeout plans the next one. The work is kept short so the demo is safe.
Top row: one long loop fills the main thread, and a click card waits after it. Bottom row: small slices of work, with a click and a redraw of the page in between them.One long looploop runs for 1.5 sclickclick waitsSmall slicessliceclicksliceredrawsliceclick gets a turn
The main thread does one job at a time, from left to right. Top: one long loop, so the click waits until it ends. Bottom: the same work in small slices, so the click and the page redraw get a turn in between.

The next code splits five units of work into slices of at most two. It does not schedule anything. It only works out how big each slice is. In real code, a timer can plan the next slice, but the browser decides when that slice gets its turn.

Split five units into slicesPop out in the code editor (opens in a new tab)JavaScript
const totalUnits = 5;
const sliceSize = 2;
const slices = [];
for (let completed = 0; completed < totalUnits; completed += sliceSize) {
  slices.push(Math.min(sliceSize, totalUnits - completed));
}
console.log(slices.join(", "));

Line 1 sets five units of work. Line 2 sets a slice size of two. Line 3 makes an empty array, slices. The loop on lines 4 to 6 adds one slice each time round. Math.min picks the smaller of two numbers, so the last slice holds only what is left. The slices are two units, two units, then one. Line 7 prints 2, 2, 1.

A timer runs after the current scriptPop out in the code editor (opens in a new tab)JavaScript
console.log("first");
setTimeout(() => console.log("later"), 0);
console.log("second");

The output order is first, second, then later. setTimeout asks the host to run a function later. Here the delay is 0, but the function still waits until the current script has finished.

setTimeout does not pause the script. It also does not run the function at the same time as the script.

There is one more way to do a big job. A Web Worker runs JavaScript on a separate thread. It has its own global names, and it can't change this page directly. It sends a message to the page instead.

This table compares the three ways. Read each row from left to right.

One long task compared with smaller tasks
How is the work done?What does the main thread do?What does the user notice?
In one long loop.It keeps running the loop until all the work is done.Clicks and page updates wait until the loop ends.
In small slices.It finishes one slice, then a timer plans the next one.The page can handle clicks and redraw between slices.
In a Web Worker.It stays free, because a separate thread runs the work.The page stays quick, but it needs a message from the worker to show the result.

This is not the full lesson on scheduling. Later, The event loop lesson explains tasks and timers in depth. For now, remember one rule: while synchronous code runs, the main thread can't handle clicks or update the page.

Step through this small example of synchronous code: a log, a function call, the function's return, and the logs after it.

Step through one function call
Step 0 of 7Ready
Your turn: follow the blue line

Step through the first log, the function call, the return, and the lines after it.

Running in
  1. script
Next: line 1
function cook(order) {  console.log("cooking " + order);  return order.toUpperCase();}const result = cook("bun");console.log(result);console.log("script end");
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Where you’ll use this

Knowing the engine from the host turns confusing errors into useful clues:

  • If the console says document is not defined, you probably ran browser code in Node.js or another runtime.
  • If it says process is not defined, you probably ran Node.js code in a browser.
  • If an older browser does not know a new method, the problem is support for that feature, not a typo.
Cart math that needs no pagePop out in the code editor (opens in a new tab)JavaScript
function getCartTotal(cart) {
  return cart.price * cart.quantity;
}
console.log(getCartTotal({ price: 3, quantity: 2 }));

Lines 1 to 3 make a function, getCartTotal. Line 2 multiplies the price by the quantity. Line 4 calls the function and prints 6. This math uses only plain values, so it runs in any host. Only the code that writes the total onto a page needs a browser.

Total two cart itemsPop out in the code editor (opens in a new tab)JavaScript
const cart = [
  { price: 3, quantity: 2 },
  { price: 2, quantity: 1 },
];
const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
console.log(total);

A real cart usually has more than one item. Lines 1 to 4 make an array of two items. reduce is an array method that goes through the items one by one and builds a single result.

Line 5 starts from 0 and adds price times quantity for each item: 3 times 2, plus 2 times 1. Line 6 prints 8. This works in any host, because it uses only arrays and numbers.

You will use this idea in everyday work:

  • MDN is a free reference website for web developers. When you read it, check whether a page is about a JavaScript language feature or a Web API. A Web API is a host API that browsers give you.
  • A package is code someone else wrote that you install and use. Before you pick one, check whether it needs Node.js APIs, browser APIs, or both.
  • When a page feels frozen, look for long synchronous work on the main thread.
  • When you compare Node.js, Deno, and Bun, ask two questions: "Which engine?" and "Which host APIs?"
A tiny debugging checklist

Before you blame JavaScript, ask three questions. Does this engine support the language feature? Does this host have the API? Is a long task blocking the main thread? These three questions solve many beginner problems.

Common misconceptions

"V8 is JavaScript."

V8 is one engine that runs JavaScript. JavaScript is the language. An engine is a program that runs it.

"Node.js and the browser are basically the same."

They run the same language, but they give you different host APIs. A browser has a page. Node.js has tools for servers and files.

"If Chrome has it, JavaScript has it."

Chrome gives you JavaScript plus many browser APIs. Some names you use in Chrome, like document, come from the browser, not from the language.

"Single-threaded means slow."

Single-threaded means one task runs at a time on the main thread. Short tasks are fine. Only long tasks that block the thread cause trouble.

"setTimeout makes work run in parallel."

Parallel means two things run at the same moment. A timer only plans work for later. You can use timers to split work into slices, but the slices still run one at a time on the main thread.

Practice: spot the layer

6 EXERCISES
Exercise 1 · Warm-upAsk your browser what exists

Open the browser console and type typeof window. Then type here what it prints.

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeCompare process

    Type typeof process in your browser console. If you like, try it again in Node.js once the next lessons have set it up.

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticePredict synchronous order

      Don't run the code yet. Write the three lines it prints, in order.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      console.log("A");
      function run() {
        console.log("B");
      }
      run();
      console.log("C");

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeFind your engine

        Use the engine table and the host experiment. Which engine does your browser most likely use?

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeSort four APIs

          Use the groups from the sorter. process.argv is the list of words typed after the command that started the program. Which group does it belong to?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          Array.prototype.map -> language
          process.argv -> Node host
          document.querySelector -> browser host
          setTimeout -> shared host API

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeUpdate a cart page safely

            The same cart code runs twice: first on the server, to build the page, and later in the browser. Work out the total in both places. Update #cart-total only when there is a page and that element exists.

            Starter codePop out in the code editor (opens in a new tab)JavaScript
            function showCartTotal(cart) {
              const total = cart.price * cart.quantity;
              document.querySelector("#cart-total").textContent = total;
              return total;
            }
            console.log(showCartTotal({ price: 3, quantity: 2 }));

            Answer, then press Check. Spacing and letter case don’t matter.

              Quiz: engines, runtimes & hosts

              7 QUESTIONS

              Check what you learned. Each answer explains why it is right or wrong.

              Lesson quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What does a JavaScript engine do?

                Choose an answer to see the explanation.

              2. Question 2 of 7Which engine does Firefox use?

                Choose an answer to see the explanation.

              3. Question 3 of 7What does this line print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                console.log(typeof globalThis);

                Choose an answer to see the explanation.

              4. Question 4 of 7Which one is a browser host API, not a language feature?

                Choose an answer to see the explanation.

              5. Question 5 of 7What does this print in a normal browser page?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                console.log(typeof process);

                Choose an answer to see the explanation.

              6. Question 6 of 7Why does a 1.5-second busy loop freeze the moving counter?

                Choose an answer to see the explanation.

              7. Question 7 of 7In what order do these logs print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                console.log("start");
                function label() {
                  console.log("inside");
                }
                label();
                console.log("end");

                Choose an answer to see the explanation.

              Key takeaways

              • V8, SpiderMonkey, and JavaScriptCore are engines: programs that run the JavaScript language.
              • Browsers, Node.js, Deno, and Bun are hosts. Each one holds an engine and adds its own APIs. Node.js, Deno, and Bun are also called runtimes.
              • Language features such as arrays, JSON, Math, and Promise work in every host. Host APIs such as document, process, timers, and storage depend on the host.
              • Ordinary page code runs one task at a time on the main thread. Long synchronous work freezes the page.
              • When code fails, ask three questions. Is this the wrong host? Is the feature not supported? Is a long task blocking the main thread?

              Remember the one-liner.
              The engine runs the language. The host gives it the world around it.

              Coming next: Manuals & specifications.

              CompleteFrontend Clear concepts. Working examples.