docs/sdk/ruby/sandbox.mdx
Create and control a microVM sandbox from Ruby. The SDK supports local and cloud backends; blocking native calls release Ruby's global VM lock (GVL) so other Ruby threads can continue running. See Lifecycle for the shared state model and Error handling for cross-SDK behavior.
gem install microsandbox
Ruby 3.1 and newer are supported. When a matching platform gem is available, it carries the native extension; otherwise the source gem requires Rust 1.85 or newer to build it locally.
require "microsandbox"
Microsandbox.install unless Microsandbox.installed?
Microsandbox::Sandbox.connect_or_create(name, **options) # => Sandbox
Reuse or create the sandbox with this name. The method connects when it is running, waits while it is starting, starts it when it is created, stopped, or crashed, and creates it only when the name is unused. Options apply only to a new sandbox, and concurrent callers reuse the same sandbox. Replace options are rejected because they request a different sandbox.
sandbox = Microsandbox::Sandbox.connect_or_create(
"worker",
image: "python",
memory: 1024,
env: { "ROLE" => "worker" }
)
Use Sandbox.create when name conflicts must remain an error, or explicit replace options when the old identity should be discarded.
Microsandbox::Sandbox.builder(name).connect_or_create # => Sandbox
Builder terminal with the same reuse, creation-option, concurrency, and replace-option behavior as Microsandbox::Sandbox.connect_or_create.
A live sandbox connection returned by create, connect_or_create, start, connect_or_start, or restart.
sandbox.id # => String
Opaque stable identity of the persisted sandbox. It remains unchanged across stop and restart and changes when a removed name is recreated. Use it for equality, logging, and correlation; do not parse it.
sandbox.wait_for_status(status) # => SandboxHandle
Wait without a built-in timeout until this exact sandbox reaches one of created, starting, running, draining, paused, stopped, or crashed. Returns a refreshed metadata handle. Use Ruby's Timeout.timeout or an application cancellation mechanism when a deadline is required.
sandbox.restart(force: false, timeout: nil, detached: false) # => Sandbox
Restart this exact sandbox. Defaults to graceful shutdown, the SDK's ten-second timeout, and attached local start. A created, stopped, or crashed sandbox starts directly; a starting sandbox is observed until it settles. Set force: true to kill, timeout: in seconds to change how long shutdown can take, or detached: true for a local background start.
On microsandbox cloud, graceful restart is supported, but timeout expiry cannot escalate to force kill. force: true is local-only, and detached: affects only local process ownership.
sandbox.destroy(force: false, timeout: nil) # => nil
Stop and remove this exact sandbox. Defaults to graceful shutdown with the SDK's ten-second timeout. Identity checks refuse to delete a same-name replacement.
Obtain a metadata handle without opening the guest-agent connection:
handle = Microsandbox::Sandbox.get("worker")
handle.id # => String
Opaque stable identity captured by this handle. Receiver lifecycle calls remain bound to this value.
handle.connect_or_start(detached: false) # => Sandbox
Connect when this exact sandbox is running, wait through starting, or start it when it is created, stopped, or crashed. draining and paused are rejected. detached: true affects only a required local start; connecting to an already-running sandbox does not change ownership.
handle.wait_for_status(status) # => SandboxHandle
Wait until this exact sandbox reaches status, returning a refreshed handle. The method does not have a built-in timeout.
handle.restart(force: false, timeout: nil, detached: false) # => Sandbox
Restart this exact sandbox with the same state and option semantics as Sandbox#restart.
handle.destroy(force: false, timeout: nil) # => nil
Stop and remove this exact sandbox. A stale handle refuses to destroy a replacement that reused the name.
Ruby currently surfaces stale identity protection through Microsandbox::Error. The message includes was replaced; unlike Rust, TypeScript, Python, and Go, the Ruby SDK does not yet expose a dedicated SandboxReplacedError subclass.
begin
stale_handle.destroy
rescue Microsandbox::Error => error
raise unless error.message.include?("was replaced")
end
See When a sandbox object is stale for the typed equivalents in the other SDKs and Names, handles, and concurrent callers for the race this prevents.
Run ruby examples/lifecycle_convergence.rb from sdk/ruby to exercise sandbox creation and reuse, stable identity, connect, wait, exec, restart, destroy, same-name replacement, and stale-handle rejection against a live microVM.