V8pedia

Isolates, Contexts & threads

Everything in the pipeline happens inside a container called an Isolate. To embed V8 (as Chrome, Node, Deno, or workerd do) you create isolates, give them Contexts to run code in, and rely on snapshots to make startup fast. This page covers V8's runtime structure and threading model.

::: info Ubiquitous language Isolate: one isolated VM instance — its own heap, GC, and (logically) single thread of JS execution. Context: a JavaScript global environment (global object + builtins). Snapshot: a serialized pre-built heap, deserialized to boot quickly. :::

Isolate: one VM, one heap

class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
 public:
  Heap* heap() { return &heap_; }

};

src/execution/isolate.h#L562-L571

An Isolate owns its heap and all the VM state (the roots, the string table, the builtins, the tiering manager). Two isolates share nothing by default — objects from one cannot reference objects in another. This isolation is what lets a browser run many independent JS environments (tabs, workers) in one process without them interfering.

Threading model

JavaScript execution in an isolate is single-threaded: at most one thread runs JS in a given isolate at a time. That assumption simplifies enormous amounts of the engine (object headers, IC updates, allocation fast paths). V8 does use many background threads — for concurrent marking, parallel scavenging, background compilation, and concurrent optimization — but those are carefully coordinated helpers, not concurrent mutators of the JS heap. To run JS on multiple threads you use multiple isolates (e.g. Web Workers), communicating by copying or via shared array buffers.

Contexts

A Context is a heap object representing a JS execution environment. The special NativeContext holds the global object plus all the built-in machinery — Array, Object, Function, the prototypes, the well-known Maps, hundreds of internal functions:

// [ extension ]  … For native contexts, it contains the global object.
V8_OBJECT class Context : public HeapObject { … };
class NativeContext : public Context { … };

src/objects/contexts.h#L499-L549

One isolate can hold many contexts (each <iframe> in a page, each vm.createContext() in Node). They share the isolate's heap but each has its own globals — which is why an array from one frame is not instanceof Array of another frame (different Array constructors live in different native contexts).

Snapshots

Initializing a fresh isolate — creating all those builtins, prototypes, and Maps by running the bootstrap code — is slow. So V8 does it once, at build time, and serializes the resulting heap into a snapshot blob that each isolate deserializes at startup:

class Snapshot : public AllStatic {
  static bool Initialize(Isolate* isolate);                 // boot from snapshot
  static MaybeDirectHandle<Context> NewContextFromSnapshot(…); // fast new context
};

src/snapshot/snapshot.h#L25-L120

  • The startup snapshot restores the isolate's base heap and builtins.

  • Context snapshots let NewContextFromSnapshot create a fresh global environment by copying, instead of re-running setup.

  • Embedders can build custom snapshots (via mksnapshot / SnapshotCreator) that include their own pre-initialized objects — Node and Chrome both do this to shave startup time.

::: tip Why this is a big deal for startup Deserializing a contiguous blob into the heap is far cheaper than executing thousands of lines of bootstrap JS/C++. Snapshotting turns "construct the standard library" from a runtime cost paid on every launch into a one-time build cost. It is one of the most effective startup optimizations in the engine, and a technique worth copying in any runtime with expensive initialization. :::

How embedders see it

Process
 ├─ Isolate A
 │    ├─ Heap (Orinoco)
 │    ├─ Context 1  (globals + builtins)
 │    └─ Context 2  (separate globals, same heap)
 └─ Isolate B  (Worker — fully independent heap)

The public C++ API (v8::Isolate, v8::Context, v8::Local<T>) mirrors these internal structures; Local<T> is the embedder-facing handle.

See also