V8 Isolates: How Edge Platforms Run Thousands of Tenants in One Process
A V8 isolate is an independent JavaScript heap and execution context inside one process. How isolates make edge runtimes start in milliseconds and pack thousands of tenants together, what isolation they provide, Spectre and the extra layers platforms add, limits, and isolates vs containers vs VMs.
Cloudflare Workers, Deno Deploy, Vercel's edge runtime and similar platforms start your code in milliseconds and run huge numbers of customers' scripts on the same machines. They can do that because they don't use a container or VM per tenant — they use V8 isolates.
What an isolate is
V8 is the JavaScript and WebAssembly engine in Chrome and Node.js. An isolate is an independent instance of the V8 runtime: its own heap, garbage collector and global objects. JavaScript running in one isolate cannot reference objects in another — there's no shared memory between them at the language level.
One operating-system process can host many isolates. Creating a new isolate (or a new context within one) costs on the order of milliseconds and a few megabytes, versus hundreds of milliseconds and tens of megabytes for a container, or more for a VM.
Process (runtime, written in C++/Rust)
├── Isolate A — tenant A's Worker
├── Isolate B — tenant B's Worker
└── Isolate C — tenant C's Worker
Why it's fast and dense
- No cold OS boot — the runtime process is already running; a request just needs an isolate.
- Snapshots — V8 can deserialize a pre-initialised heap snapshot, skipping setup work.
- Shared code — the runtime's binary and built-in code are shared; only each tenant's heap is separate.
- Fine-grained scheduling — idle isolates cost little; thousands can sit on one machine.
This makes per-request isolation and scale-to-zero economical. (What is serverless?)
What isolation you actually get
Language-level isolation: memory safety of the JavaScript/Wasm runtime prevents one isolate from reading another's objects. The platform controls which APIs exist (fetch, KV, no filesystem, no raw sockets), so tenants have no ambient authority beyond what's exposed — similar in spirit to WASI capabilities. (WebAssembly sandboxing)
But isolates share a process and an address space. Two big risks:
- V8 bugs — a memory-corruption bug in the engine (JIT bugs are found regularly) can let code escape its heap and read or write the whole process.
- Side channels — Spectre-class attacks can, in principle, read memory from the same address space via speculative execution and timing.
Chrome's own answer is site isolation: different sites in different processes, because in-process isolation alone isn't considered sufficient against Spectre.
The extra layers platforms add
Production isolate platforms don't rely on V8 alone. Cloudflare has described a layered approach for Workers, including:
- A second sandbox around the runtime process — the process itself runs with OS-level restrictions (namespaces, seccomp) so an engine escape lands in a locked-down process.
- Spectre mitigations — removing high-precision timers and concurrency primitives that make timing attacks practical (e.g.
Date.now()doesn't advance during execution), and monitoring for attack patterns. - Dynamic process isolation — moving suspicious or high-risk tenants into separate processes.
- Rapid patching of V8 security fixes, often faster than Chrome's release cycle.
Isolation is a stack, not a single mechanism.
Limits that come with the model
- CPU time limits per request (milliseconds to minutes depending on plan) — long jobs don't fit.
- Memory limits per isolate (often ~128 MB).
- No arbitrary native code — no
child_process, no native Node add-ons; only what compiles to JS/Wasm. - Partial Node.js compatibility — many npm packages work via compatibility layers; anything expecting a real OS doesn't.
- No local filesystem state — persistence goes through platform storage (KV, D1/SQL, R2, Durable Objects).
Isolates vs containers vs VMs
| V8 isolates | Containers | MicroVMs / VMs | |
|---|---|---|---|
| Start-up | ~ms | 100s of ms | 100 ms – seconds |
| Density | Thousands per process | Dozens–hundreds per host | Dozens per host |
| Boundary | Language runtime (+ process sandbox) | Shared kernel | Hypervisor |
| Runs arbitrary binaries | No | Yes | Yes |
| Best for | Short request handlers, edge logic | General apps | Untrusted, long-running, full-OS workloads |
(Containers vs virtual machines, Firecracker vs gVisor vs containers)
Using isolates in your own product
If you want to run customer-supplied JavaScript (formulas, workflow steps, webhooks transforms):
- Libraries like
isolated-vmexpose V8 isolates to Node.js with memory and time limits. - Don't use Node's
vmmodule as a security boundary — its docs say plainly it isn't one. - Treat in-process isolation as one layer; run the host process sandboxed, and for mutually hostile tenants, separate processes or VMs. (Run AI-generated code safely)
EasySpawn is built for the workloads isolates can't hold — full apps, databases and AI agents running real toolchains — with a VM boundary around each server. See how it works or join the waitlist.
Related: WebAssembly as a Sandbox · Firecracker vs gVisor vs Containers · What Is Serverless? · Kata Containers
Keep reading
WebAssembly as a Sandbox: Running Untrusted Code With Wasmtime and WASI
WebAssembly's design makes it a strong in-process sandbox: linear memory, no ambient authority, and capability-based access through WASI. How the isolation works, limiting CPU with fuel and epochs, memory limits, the component model, real uses for plugins and user code, and where it falls short.
Firecracker vs gVisor vs Containers: Choosing Isolation for Untrusted Code
Containers share a kernel; gVisor intercepts it; Firecracker gives each workload its own. How the three isolation models actually work, what each costs in performance and compatibility, and how to match the boundary to the threat — for AI agents, multi-tenant platforms, and code execution.