Machine

A machine is a microVM instance that provides an isolated execution environment.

Creating a Machine

import { Machine } from 'smolvm';

// Basic creation
const machine = await Machine.create({ name: 'my-machine' });

// With configuration
const machine = await Machine.create({
  name: 'configured-machine',
  mounts: [
    { source: '/host/code', target: '/workspace' }
  ],
  resources: {
    cpus: 2,
    memoryMb: 1024
  }
});
from smolvm import Machine, MachineConfig, MountSpec, ResourceSpec

# Basic creation
machine = await Machine.create(MachineConfig(name="my-machine"))

# With configuration
config = MachineConfig(
    name="configured-machine",
    mounts=[
        MountSpec(source="/host/code", target="/workspace")
    ],
    resources=ResourceSpec(
        cpus=2,
        memory_mb=1024
    )
)
machine = await Machine.create(config)

Configuration Options

OptionTypeDefaultDescription
namestringrequiredUnique machine identifier
serverUrlstringhttp://127.0.0.1:8080Server URL
mountsMountSpec[][]Volume mounts
portsPortSpec[][]Port forwarding
resourcesResourceSpecdefaultCPU and memory limits

Lifecycle Methods

start()

Creates and starts the machine. Called automatically by Machine.create().

const machine = new Machine({ name: 'manual' });
await machine.start();
machine = Machine(MachineConfig(name="manual"))
await machine.start()

stop()

Stops the machine. The machine can be restarted.

await machine.stop();
await machine.stop()

delete()

Deletes the machine. This is permanent.

await machine.delete();
await machine.delete()

status()

Gets the current machine status.

const info = await machine.status();
console.log(info.state); // 'running', 'stopped', etc.
info = await machine.status()
print(info.state)  # 'running', 'stopped', etc.

Execution Methods

TIP

`exec` and `run` calls — running commands inside a machine — are never charged and never rate-limited. Run as many as you want.

exec()

Execute a command directly in the microVM.

const result = await machine.exec(['ls', '-la', '/']);

// With options
const result = await machine.exec(['long-running-task'], {
  timeout: 60000, // 60 seconds
  env: { MY_VAR: 'value' },
  workdir: '/tmp'
});
result = await machine.exec(["ls", "-la", "/"])

# With options
result = await machine.exec(
    ["long-running-task"],
    timeout=60.0,  # 60 seconds
    env={"MY_VAR": "value"},
    workdir="/tmp"
)

run()

Run a command in a container image.

const result = await machine.run(
  'python:3.12-alpine',
  ['python', '-c', 'print("Hello")']
);

// With options
const result = await machine.run(
  'node:22-alpine',
  ['node', 'script.js'],
  {
    timeout: 30000,
    env: { NODE_ENV: 'production' }
  }
);
result = await machine.run(
    "python:3.12-alpine",
    ["python", "-c", "print('Hello')"]
)

# With options
result = await machine.run(
    "node:22-alpine",
    ["node", "script.js"],
    timeout=30.0,
    env={"NODE_ENV": "production"}
)

Best Practices

Use Context Managers (Python)

Python’s async context manager ensures cleanup:

async with Machine(config) as machine:
    await machine.start()
    # ... use machine
# Automatically stops, deletes, and closes

Use withMachine (TypeScript)

The helper function ensures cleanup:

const result = await withMachine(config, async (machine) => {
  return machine.exec(['whoami']);
});
// Automatically stops and deletes

Reuse Machines

For multiple commands, reuse the same machine:

// Good - one machine, multiple commands
const machine = await Machine.create({ name: 'worker' });
for (const task of tasks) {
  await machine.exec(task.command);
}
await machine.stop();

// Bad - new machine per command (slow)
for (const task of tasks) {
  await quickExec(task.command); // Creates new machine each time
}