CreateOS Sandbox SDKs
Create, control, and clean up isolated Linux sandboxes from your application. Choose TypeScript, Go, or Python in any example, the selection stays in sync across the page.
| Language | Package | Requirements |
|---|---|---|
| TypeScript | @nodeops-createos/sandbox | Node.js 20+, Bun, Deno, edge runtimes, or a browser |
| Go | github.com/NodeOps-app/createos-go-sdk | Go 1.25+ |
| Python | createos-sandbox | Python 3.10+ |
Every SDK reads CREATEOS_SANDBOX_API_KEY and
CREATEOS_SANDBOX_BASE_URL from the environment.
Install the SDK
npm install @nodeops-createos/sandboxgo get github.com/NodeOps-app/createos-go-sdkpip install createos-sandboxCreate a sandbox and run a command
The create call returns a connected sandbox that is ready to accept commands. Always destroy it when the work is complete.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
});
try {
const response = await sandbox.runCommand("echo", ["Hello from CreateOS"]);
console.log(response.result.stdout);
} finally {
await sandbox.destroy();
}package main
import (
"context"
"fmt"
"log"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb",
RootFS: "devbox:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
response, err := instance.RunCommand(ctx, structs.RunCommandRequest{
Command: "echo",
Arguments: []string{"Hello from CreateOS"},
}, structs.ExecOptions{})
if err != nil {
log.Fatal(err)
}
fmt.Print(response.Result.StandardOutput)
}from createos import Client, CreateSandboxRequest, RunCommandRequest
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-1vcpu-1gb", rootfs="devbox:1")
)
try:
response = sandbox.run_command(
RunCommandRequest(
command="echo", arguments=["Hello from CreateOS"]
)
)
print(response.result.standard_output, end="")
finally:
sandbox.destroy()Stream command output
Receive output as it is produced instead of waiting for the command to finish. These snippets use the running sandbox created above.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
});
try {
const command = "for n in 1 2 3; do echo result-$n; sleep 1; done";
for await (const event of sandbox.streamCommand("sh", ["-c", command])) {
if (event.type === "stdout") process.stdout.write(event.data);
}
} finally {
await sandbox.destroy();
}package main
import (
"context"
"errors"
"fmt"
"io"
"log"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb", RootFS: "devbox:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
command := "for n in 1 2 3; do echo result-$n; sleep 1; done"
stream, err := instance.StreamCommand(ctx, structs.RunCommandRequest{
Command: "sh", Arguments: []string{"-c", command},
}, structs.ExecOptions{})
if err != nil {
log.Fatal(err)
}
defer stream.Close()
for {
event, err := stream.Receive()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
if event.Type == structs.ExecStreamEventStdout {
fmt.Print(event.Data)
}
}
}from createos import (
Client,
CreateSandboxRequest,
ExecStreamEventType,
RunCommandRequest,
)
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-1vcpu-1gb", rootfs="devbox:1")
)
try:
command = "for n in 1 2 3; do echo result-$n; sleep 1; done"
request = RunCommandRequest(command="sh", arguments=["-c", command])
with sandbox.stream_command(request) as stream:
for event in stream:
if event.type is ExecStreamEventType.STDOUT:
print(event.data, end="")
finally:
sandbox.destroy()Upload files
Upload a file without shell escaping. These snippets assume the
sandbox or instance from the previous example is still running.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
});
try {
await sandbox.files.upload("/workspace/hello.txt", "Hello from TypeScript");
const file = await sandbox.files.download("/workspace/hello.txt");
console.log(new TextDecoder().decode(file));
} finally {
await sandbox.destroy();
}package main
import (
"context"
"fmt"
"io"
"log"
"strings"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb", RootFS: "devbox:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
content := strings.NewReader("Hello from Go")
if err := instance.Files().Upload(ctx, "/workspace/hello.txt", content); err != nil {
log.Fatal(err)
}
file, err := instance.Files().Download(ctx, "/workspace/hello.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
contents, err := io.ReadAll(file)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(contents))
}from createos import Client, CreateSandboxRequest
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-1vcpu-1gb", rootfs="devbox:1")
)
try:
sandbox.files.upload("/workspace/hello.txt", b"Hello from Python")
with sandbox.files.download("/workspace/hello.txt") as file:
print(file.read().decode())
finally:
sandbox.destroy()Publish a live preview
Start a service and generate its public URL. Create the sandbox with ingress enabled before running this example.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
ingress_enabled: true,
});
try {
await sandbox.processes.create({
cmd: "python3",
args: ["-m", "http.server", "8080", "--bind", "0.0.0.0"],
});
await sandbox.waitForPortReady(8080);
console.log(sandbox.previewUrl(8080));
} finally {
await sandbox.destroy();
}package main
import (
"context"
"fmt"
"log"
"time"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb", RootFS: "devbox:1", IngressEnabled: true,
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
_, err = instance.Processes().Create(ctx, structs.ManagedProcessCreateRequest{
Command: "python3",
Arguments: []string{"-m", "http.server", "8080", "--bind", "0.0.0.0"},
})
if err != nil {
log.Fatal(err)
}
if err := instance.WaitForPort(ctx, "127.0.0.1", 8080, 15*time.Second); err != nil {
log.Fatal(err)
}
previewURL, err := instance.PreviewURL(8080)
if err != nil {
log.Fatal(err)
}
fmt.Println(previewURL)
}from createos import (
Client,
CreateSandboxRequest,
ManagedProcessCreateRequest,
)
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(
shape="s-1vcpu-1gb", rootfs="devbox:1", ingress_enabled=True
)
)
try:
sandbox.processes.create(
ManagedProcessCreateRequest(
command="python3",
arguments=["-m", "http.server", "8080", "--bind", "0.0.0.0"],
)
)
sandbox.wait_for_port(8080, timeout=15)
print(sandbox.preview_url(8080))
finally:
sandbox.destroy()Run managed processes
Keep a stable process ID, reconnect to output, send input, and wait for the entire process tree.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
});
try {
const process = await sandbox.processes.create({
cmd: "sh",
args: ["-c", "echo finished"],
});
const result = await sandbox.processes.wait(process.process_id, {
scope: "tree",
});
console.log(result.exit_code);
} finally {
await sandbox.destroy();
}package main
import (
"context"
"fmt"
"log"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb", RootFS: "devbox:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
process, err := instance.Processes().Create(ctx, structs.ManagedProcessCreateRequest{
Command: "sh", Arguments: []string{"-c", "echo finished"},
})
if err != nil {
log.Fatal(err)
}
result, err := instance.Processes().Wait(ctx, process.ProcessID,
structs.ManagedProcessWaitOptions{Scope: structs.ManagedProcessWaitScopeTree},
)
if err != nil {
log.Fatal(err)
}
fmt.Println(*result.ExitCode)
}from createos import (
Client,
CreateSandboxRequest,
ManagedProcessCreateRequest,
ManagedProcessWaitOptions,
ManagedProcessWaitScope,
)
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-1vcpu-1gb", rootfs="devbox:1")
)
try:
process = sandbox.processes.create(
ManagedProcessCreateRequest(
command="sh", arguments=["-c", "echo finished"]
)
)
result = sandbox.processes.wait(
process.process_id,
ManagedProcessWaitOptions(scope=ManagedProcessWaitScope.TREE),
)
print(result.exit_code)
finally:
sandbox.destroy()Spawn an interactive terminal
Create a PTY-backed shell, resize its terminal, send commands, and reconnect to its retained output after it exits.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-1vcpu-1gb",
rootfs: "devbox:1",
});
try {
const terminal = await sandbox.processes.create({
cwd: "/workspace",
pty: { rows: 24, cols: 80 },
});
await sandbox.processes.resize(terminal.process_id, {
rows: 32,
cols: 100,
});
await sandbox.processes.input(
terminal.process_id,
"echo 'CreateOS terminal ready'; uname -s; pwd; exit\n",
);
const result = await sandbox.processes.wait(terminal.process_id, {
scope: "tree",
});
if (result.exit_code !== 0) {
throw new Error(`Terminal exited with code ${result.exit_code}`);
}
for await (const event of sandbox.processes.connect(terminal.process_id)) {
if (event.type === "data" && event.stream === "pty") {
process.stdout.write(event.data);
}
}
} finally {
await sandbox.destroy();
}package main
import (
"context"
"errors"
"fmt"
"io"
"log"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-1vcpu-1gb", RootFS: "devbox:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
terminal, err := instance.Processes().Create(ctx, structs.ManagedProcessCreateRequest{
WorkingDirectory: "/workspace",
PTY: &structs.PTYSize{Rows: 24, Cols: 80},
})
if err != nil {
log.Fatal(err)
}
if err := instance.Processes().Resize(ctx, terminal.ProcessID,
structs.PTYSize{Rows: 32, Cols: 100}); err != nil {
log.Fatal(err)
}
_, err = instance.Processes().Input(ctx, terminal.ProcessID,
"echo 'CreateOS terminal ready'; uname -s; pwd; exit\n")
if err != nil {
log.Fatal(err)
}
result, err := instance.Processes().Wait(ctx, terminal.ProcessID,
structs.ManagedProcessWaitOptions{Scope: structs.ManagedProcessWaitScopeTree},
)
if err != nil {
log.Fatal(err)
}
if result.ExitCode == nil || *result.ExitCode != 0 {
log.Fatalf("terminal exited with code %v", result.ExitCode)
}
stream, err := instance.Processes().Connect(ctx, terminal.ProcessID,
structs.ManagedProcessConnectOptions{})
if err != nil {
log.Fatal(err)
}
defer stream.Close()
for {
event, err := stream.Receive()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
if event.Type == structs.ManagedProcessConnectEventData &&
event.Stream == structs.ManagedProcessStreamPTY {
fmt.Print(string(event.Data))
}
}
}from createos import (
Client,
CreateSandboxRequest,
ManagedProcessConnectEventType,
ManagedProcessCreateRequest,
ManagedProcessStream,
ManagedProcessWaitOptions,
ManagedProcessWaitScope,
PTYSize,
)
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-1vcpu-1gb", rootfs="devbox:1")
)
try:
processes = sandbox.processes
terminal = processes.create(
ManagedProcessCreateRequest(
working_directory="/workspace",
pty=PTYSize(rows=24, cols=80),
)
)
processes.resize(terminal.process_id, PTYSize(rows=32, cols=100))
processes.input(
terminal.process_id,
"echo 'CreateOS terminal ready'; uname -s; pwd; exit\\n",
)
result = processes.wait(
terminal.process_id,
ManagedProcessWaitOptions(scope=ManagedProcessWaitScope.TREE),
)
if result.exit_code != 0:
raise RuntimeError(
f"Terminal exited with code {result.exit_code}"
)
with processes.connect(terminal.process_id) as stream:
for event in stream:
if (
event.type is ManagedProcessConnectEventType.DATA
and event.stream is ManagedProcessStream.PTY
):
print(event.data.decode(errors="replace"), end="")
finally:
sandbox.destroy()Automate a cloud desktop
Open the NodeOps website in a graphical cloud browser and capture a validated
PNG screenshot. This example requires the desktop:1 image.
import { createClient } from "@nodeops-createos/sandbox";
const client = createClient();
const sandbox = await client.createSandbox({
shape: "s-2vcpu-4gb",
rootfs: "desktop:1",
});
try {
let screen;
for (let attempt = 0; attempt < 60; attempt++) {
screen = await sandbox.computer.screen({ screenId: "screen-0" })
.catch(() => undefined);
if (screen) break;
await new Promise((resolve) => setTimeout(resolve, 2_000));
}
if (!screen) throw new Error("Desktop did not become ready");
const target = "https://createos.sh";
await sandbox.computer.open(target, { screenId: "screen-0" });
await new Promise((resolve) => setTimeout(resolve, 3_000));
const screenshot = await sandbox.computer.screenshot({
screenId: "screen-0",
timeoutMs: 45_000,
});
const view = new DataView(screenshot);
const width = view.getUint32(16, false);
const height = view.getUint32(20, false);
console.log(`Opened ${target} and captured a ${width}x${height} screenshot`);
} finally {
await sandbox.destroy();
}package main
import (
"context"
"fmt"
"image/png"
"log"
"time"
"github.com/NodeOps-app/createos-go-sdk/sandbox"
"github.com/NodeOps-app/createos-go-sdk/structs"
)
func main() {
ctx := context.Background()
client, err := sandbox.NewClient()
if err != nil {
log.Fatal(err)
}
instance, err := client.CreateSandbox(ctx, structs.CreateSandboxRequest{
Shape: "s-2vcpu-4gb", RootFS: "desktop:1",
})
if err != nil {
log.Fatal(err)
}
defer instance.Destroy(context.Background())
options := structs.ComputerScreenOptions{ScreenID: structs.ComputerScreen0}
for attempt := 0; attempt < 60; attempt++ {
_, err = instance.Computer().Screen(ctx, options)
if err == nil {
break
}
time.Sleep(2 * time.Second)
}
if err != nil {
log.Fatal("desktop did not become ready: ", err)
}
target := "https://createos.sh"
if err := instance.Computer().Open(ctx,
structs.ComputerOpenRequest{Target: target}, options); err != nil {
log.Fatal(err)
}
time.Sleep(3 * time.Second)
screenshot, err := instance.Computer().Screenshot(ctx, structs.ComputerScreenshotOptions{
ComputerScreenOptions: options,
})
if err != nil {
log.Fatal(err)
}
defer screenshot.Close()
image, err := png.DecodeConfig(screenshot)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Opened %s and captured a %dx%d screenshot\n",
target, image.Width, image.Height)
}import struct
import time
from createos import (
APIError,
Client,
ComputerOpenRequest,
ComputerScreenID,
ComputerScreenOptions,
ComputerScreenshotOptions,
CreateSandboxRequest,
)
with Client() as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(shape="s-2vcpu-4gb", rootfs="desktop:1")
)
try:
computer = sandbox.computer
options = ComputerScreenOptions(screen_id=ComputerScreenID.SCREEN_0)
for _ in range(60):
try:
computer.screen(options)
break
except APIError:
time.sleep(2)
else:
raise TimeoutError("Desktop did not become ready")
target = "https://nodeops.network"
computer.open(ComputerOpenRequest(target=target), options)
time.sleep(3)
with computer.screenshot(
ComputerScreenshotOptions(
screen_id=ComputerScreenID.SCREEN_0, timeout=45
)
) as screenshot:
payload = screenshot.read()
# PNG stores width and height as big-endian integers in the IHDR chunk.
width, height = struct.unpack(">II", payload[16:24])
print(f"Opened {target} and captured a {width}x{height} screenshot")
finally:
sandbox.destroy()Source and API reference
- TypeScript SDK on GitHub
- TypeScript API reference
- Go SDK on GitHub
- Go API reference
- Python SDK on GitHub
- Python API reference
Related
- Limits & defaults for what
createSandboxcan ask for on each plan. - REST API if you are not on TypeScript, Go or Python; every SDK call is one documented endpoint.
- Packages: @nodeops-createos/sandbox on npm · Python SDK on GitHub · source and issues: GitHub. Provider-agnostic use through ComputeSDK (
@computesdk/createos-sandbox).