Isolate JavaScript Backend Limitations vs. Container Backend in Cloudflare Computer

The Isolate JavaScript backend in Cloudflare Computer enforces strict sandboxing with bounded concurrency, no native code execution, and restricted network access, while the Container backend provides full Linux containers with unlimited concurrency, native binary support, and direct filesystem access.

The Cloudflare Computer SDK allows developers to execute code within a Workspace using two distinct backend architectures. Understanding the architectural trade-offs between the Isolate (WorkerJavaScriptBackend) and Container (CloudflareContainerBackend) execution environments is critical for selecting the appropriate runtime for your workload.

Core Architectural Differences

The two backends diverge fundamentally in how they isolate and execute user code.

Execution Environment Model

Isolate JavaScript Backend: Each execution spawns a fresh Cloudflare Dynamic Worker (V8 isolate). The runtime is created per execution and destroyed immediately after the event stream terminates. No process state persists between invocations.

Container Backend: Executes inside a full Linux container that remains alive for the lifetime of the Durable Object. The container behaves like a standard Node.js process with persistent execution state.

This difference is implemented in packages/computer/src/backends/worker-javascript/worker-javascript.ts for the isolate backend and packages/computer/src/backends/container/index.ts for the container backend.

Concurrency and Resource Limits

Concurrent Execution Caps

The Isolate backend enforces a hard limit of 24 concurrent executions by default. Per the source code in worker-javascript.ts, attempting to start additional executions returns an EEXEC_BUSY error code. This protects the host from resource exhaustion but creates backpressure for high-throughput workloads.

The Container backend imposes no per-execution concurrency cap. Container-level resource limits apply, but multiple processes and threads can spawn freely within those bounds.

CPU and Timeout Constraints

Limit Type Isolate Backend Container Backend
CPU quota Fixed per-isolate allocation Bound by container resources
Wall-clock timeout Enforced via maxHostCallMs Configurable, supports long-running processes
Execution lifetime Terminates with event stream Persists across Durable Object idle periods

The isolate's strict timeout enforcement prevents runaway computations but makes the backend unsuitable for batch processing or sustained workloads.

Network and Filesystem Access Restrictions

Outbound Networking

By default, the Isolate backend sets globalOutbound to null, blocking all outbound network calls. Selective enablement requires explicit configuration:

  • allowGitNetwork: Permits Git protocol operations
  • allowArtifactNetwork: Permits artifact registry access

The Container backend provides full outbound networking subject to standard Cloudflare Container egress policies, requiring no special flags for HTTP, DNS, or other protocols.

Filesystem Isolation

The Isolate backend routes all file I/O through the Workspace virtual filesystem (node:fs shim). Direct host filesystem access is impossible. Path confinement checks in worker-javascript.ts ensure all operations remain within the Workspace root.

The Container backend mounts the Workspace VFS while retaining full container filesystem access, including /tmp, /usr, and other standard paths. This enables temporary file usage, package installation, and interaction with system directories.

Native Code and Module Support

Binary Execution

The Isolate backend cannot load native Node.js addons or execute system binaries. Only pure JavaScript/TypeScript modules run in the V8 isolate.

The Container backend executes native binaries directly and loads compiled addons. The source code demonstrates this with modules like fuse-native that require native bindings.

Module Import Constraints

Isolate backend limitations (from docs/17_isolate_javascript.md):

  • Bare imports must be pre-registered at backend construction time
  • Dynamic imports require static string literals
  • No support for runtime require() resolution

Container backend capabilities:

  • Standard npm module resolution
  • Dynamic require() and import() without pre-registration
  • Full Node.js module compatibility

Environment and Security Model

Environment Variable Exposure

The Isolate backend exposes only the env object passed to runtime.exec() via process.env. The Durable Object's own environment is never merged, preventing secret leakage between executions.

The Container backend inherits the complete Durable Object environment, including secrets and configuration variables defined at deployment.

Sandbox Strength Trade-offs

Security Aspect Isolate Backend Container Backend
Fresh sandbox per execution Yes No (container persists)
Host binding access Blocked Available via container interfaces
Import restrictions Strict whitelist Standard Node.js resolution
Execution isolation Process-level Container-level
Attack surface Minimal Larger shared runtime

The Isolate backend's strong confinement—fresh sandbox, limited imports, strict path checks—prioritizes security over flexibility. The Container backend's weaker sandboxing accepts greater risk in exchange for operational convenience.

State Persistence and Lifecycle

Execution State Durability

In the Isolate backend, execution state exists only while the isolate runs. The documentation in docs/17_isolate_javascript.md notes that once evicted, "any un-drained output is lost." Clients must call handle.result() or maintain the stream to capture results.

Container backend processes continue execution after the Durable Object becomes idle because the container remains alive until explicitly stopped. This supports background processing and deferred result retrieval.

Capability Call Overhead

Every capability call in the Isolate backend (e.g., ws:git, ws:artifacts) traverses the isolate boundary with:

  • Additional validation layers
  • Byte-limit enforcement
  • Cancellation handling logic

Container backend calls execute directly from the container process, bypassing isolation-layer overhead while maintaining RPC contract compliance.

Practical Selection Guide

Choose the Isolate JavaScript backend when:

  • Running untrusted or third-party code
  • Executing short-lived, pure-JavaScript functions
  • Minimizing attack surface is paramount
  • Network and filesystem access can be tightly constrained

Choose the Container backend when:

  • Native binaries or compiled modules are required
  • Long-running processes or background tasks are needed
  • Full network and filesystem flexibility is essential
  • Concurrency demands exceed 24 simultaneous executions

Code Examples

Isolate JavaScript Backend Configuration

import { Workspace } from "@cloudflare/computer";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

const ws = new Workspace({
  storage: ctx.storage,
  backends: [
    new WorkerJavaScriptBackend({
      loader: env.LOADER,
      root: "/workspace",
      access: "read-write",
      maxTimeoutMs: 180_000,
      modules: {
        "math-kit": `export const double = v => v * 2;`,
      },
    }),
  ],
});

const handle = await ws.runtime.exec(
  `
    import { double } from "math-kit";
    export default async function main(input) {
      return { result: double(input.value) };
    }
  `,
  { backend: "worker-javascript", input: { value: 7 } }
);
const { result } = await handle.result();

Container Backend Configuration

import { Workspace } from "@cloudflare/computer";
import { CloudflareContainerBackend } from "@cloudflare/computer/backends/container";

const ws = new Workspace({
  storage: ctx.storage,
  backends: [
    new CloudflareContainerBackend({
      root: "/workspace",
      allowGitNetwork: true,
    }),
  ],
});

const handle = await ws.runtime.exec(
  `
    import { execSync } from "node:child_process";
    export default async function main() {
      const out = execSync("uname -a", { encoding: "utf8" });
      return { sysInfo: out };
    }
  `,
  { backend: "container", input: {} }
);
const { sysInfo } = await handle.result();

Summary

  • Concurrency: Isolate backend caps at 24 concurrent executions; Container backend has no hard per-execution limit
  • Native code: Isolate backend prohibits native binaries and Node addons; Container backend supports both
  • Network access: Isolate backend blocks outbound traffic by default; Container backend provides full networking
  • Filesystem: Isolate backend uses Workspace VFS exclusively; Container backend mounts VFS plus container filesystem
  • State persistence: Isolate backend loses state on eviction; Container backend maintains processes across idle periods
  • Security model: Isolate backend offers stronger sandboxing; Container backend trades isolation for flexibility

Frequently Asked Questions

What happens when Isolate backend concurrency exceeds 24 executions?

The backend returns an EEXEC_BUSY error and rejects the new execution attempt. Implement queue-based request buffering or migrate to the Container backend for higher throughput requirements.

Can the Isolate backend access environment variables defined in the Durable Object?

No. The Isolate backend exposes only the env object explicitly passed to runtime.exec(). This intentional isolation prevents secrets from leaking between executions in multi-tenant scenarios.

Is it possible to run shell commands in the Isolate JavaScript backend?

No. The node:child_process module and system binary execution are unavailable. All functionality must be implemented in pure JavaScript/TypeScript or delegated to capability calls like ws:git.

Why does the Container backend require allowGitNetwork when the Isolate backend has the same flag?

The flag naming creates consistency, but the underlying implementation differs. In the Isolate backend, allowGitNetwork explicitly punches through the null default for globalOutbound. In the Container backend, it configures egress policy without overcoming a fundamental network block.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →