modal.Sandbox
class Sandbox(modal.object.Object)A Sandbox object lets you interact with a running sandbox. This API is similar to Python’s asyncio.subprocess.Process.
Refer to the guide on how to spawn and use sandboxes.
hydrate
hydrate(self, client=None)Synchronize the local object with its identity on the Modal server.
It is rarely necessary to call this method explicitly, as most operations will lazily hydrate when needed. The main use case is when you need to access object metadata, such as its ID.
Added in v0.72.39: This method replaces the deprecated .resolve() method.
create
create(*args, app=None, name=None, tags=None, image=None, env=None,
secrets=None, network_file_systems={}, timeout=300, idle_timeout=None,
workdir=None, gpu=None, cloud=None, region=None, cpu=None, memory=None,
block_network=False, outbound_cidr_allowlist=None,
outbound_domain_allowlist=None, inbound_cidr_allowlist=None, volumes={},
pty=False, encrypted_ports=[], h2_ports=[], unencrypted_ports=[],
custom_domain=None, proxy=None, include_oidc_identity_token=False,
readiness_probe=None, verbose=False, experimental_options=None,
_experimental_enable_snapshot=False, client=None, environment_name=None,
pty_info=None, cidr_allowlist=None)Create a new Sandbox to run untrusted, arbitrary code.
The Sandbox’s corresponding container will be created asynchronously.
Parameters
*.). pty instead. pty will override pty_info. Returns
A Sandbox object representing the created sandbox which can be used to interact with the sandbox.
Raises
AlreadyExistsError: If a sandbox with the same name already exists.
Usage
app = modal.App.lookup('sandbox-hello-world', create_if_missing=True)
sandbox = modal.Sandbox.create("echo", "hello world", app=app)
print(sandbox.stdout.read())
sandbox.wait()detach
detach(self)Disconnects your client from the sandbox and cleans up resources assoicated with the connection.
Be sure to only call detach when you are done interacting with the sandbox. After calling detach,
any operation using the Sandbox object is not guaranteed to work anymore. If you want to continue interacting
with a running sandbox, use Sandbox.from_id to get a new Sandbox object.
from_name
from_name(app_name, name, *, environment_name=None, client=None)Get a running Sandbox by name from a deployed App.
A Sandbox’s name is the name argument passed to Sandbox.create.
Parameters
Client.from_env() when omitted. Returns
A Sandbox handle for the running sandbox.
Raises
NotFoundError: If no running sandbox exists with the given name.
from_id
from_id(sandbox_id, client=None)Construct a Sandbox from an id and look up the Sandbox result.
The ID of a Sandbox object can be accessed using .object_id.
Parameters
Returns
A Sandbox handle with any available result metadata populated from the server.
get_tags
get_tags(self)Fetches any tags (key-value pairs) currently attached to this Sandbox from the server.
Returns
Tags as a map from tag name to tag value.
set_tags
set_tags(self, tags, *, client=None)Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in Sandbox.list.
Parameters
snapshot_filesystem
snapshot_filesystem(self, timeout=55, *, ttl=30 * 24 * 3600)Snapshot the filesystem of the Sandbox.
Parameters
modal.exception.TimeoutError is raised. (Default is 55)ttl seconds (default: 30 days). Pass ttl=None to retain the image indefinitely. (Default is 30 * 24 * 3600)Returns
An Image object which can be used to spawn a new
Sandbox with the same filesystem.
mount_image
mount_image(self, path, image, *, _experimental_encryption_key=None)Mount an Image at a specified path in a running Sandbox.
path should be a directory that is not the root path (/). If the path doesn’t exist
it will be created. If it exists and contains data, the previous directory will be replaced
by the mount.
The image argument supports any Image that has an object ID, including:
- Images built using
image.build() - Images referenced by ID, e.g.
Image.from_id(...) - Filesystem/directory snapshots, e.g. created by
.snapshot_directory()or.snapshot_filesystem() - Empty images created with
Image.from_scratch()
Parameters
/). path (must be built, referenced by ID, or snapshot-based as described above). Usage
user_project_snapshot: Image = sandbox_session_1.snapshot_directory("/user_project")
# You can later mount this snapshot to another Sandbox:
sandbox_session_2 = modal.Sandbox.create(...)
sandbox_session_2.mount_image("/user_project", user_project_snapshot)
sandbox_session_2.filesystem.list_files("/user_project")unmount_image
unmount_image(self, path)Unmount a previously mounted Image from a running Sandbox.
path must be the exact mount point that was passed to .mount_image().
After unmounting, the underlying Sandbox filesystem at that path becomes
visible again.
Parameters
snapshot_directory
snapshot_directory(self, path, *, timeout=55, ttl=30 * 24 * 3600,
_experimental_encryption_key=None)Snapshot a directory in a running Sandbox, creating a new Image with its content.
timeout If the snapshot does not return within that window, the call is cancelled
and modal.exception.TimeoutError is raised.
ttl The resulting Image is retained for ttl seconds (default: 30 days)
Pass ttl=None to retain the image indefinitely.
Parameters
Returns
An Image containing the directory contents.
Usage
user_project_snapshot: Image = sandbox_session_1.snapshot_directory("/user_project")
# You can later mount this snapshot to another Sandbox:
sandbox_session_2 = modal.Sandbox.create(...)
sandbox_session_2.mount_image("/user_project", user_project_snapshot)
sandbox_session_2.filesystem.list_files("/user_project")wait
wait(self, raise_on_termination=True)Wait for the Sandbox to finish running.
Parameters
wait_until_ready
wait_until_ready(self, *, timeout=300)Wait for the Sandbox readiness probe to report that the Sandbox is ready.
The Sandbox must be configured with a readiness_probe in order to use this method.
Parameters
Usage
app = modal.App.lookup('sandbox-wait-until-ready', create_if_missing=True)
sandbox = modal.Sandbox.create(
"python3", "-m", "http.server", "8080",
readiness_probe=modal.Probe.with_tcp(8080),
app=app,
)
sandbox.wait_until_ready()tunnels
tunnels(self, timeout=50)Get Tunnel metadata for the sandbox.
NOTE: Previous to client v0.64.153, this
returned a list of TunnelData objects.
Parameters
Returns
A dictionary mapping container port to Tunnel metadata.
Raises
SandboxTimeoutError: If the tunnels are not available after the timeout.
create_connect_token
create_connect_token(self, user_metadata=None)Create a token for making HTTP connections to the Sandbox.
Also accepts an optional user_metadata string or dict to associate with the token. This metadata will be added to the headers by the proxy when forwarding requests to the Sandbox.
Parameters
Returns
URL and token credentials for connecting to the sandbox over HTTP.
reload_volumes
reload_volumes(self)Reload all Volumes mounted in the Sandbox.
Added in v1.1.0.
terminate
terminate(self, *, wait=False)Terminate Sandbox execution.
This is a no-op if the Sandbox has already finished running.
Parameters
Returns
The sandbox exit code when wait is True; otherwise None.
poll
poll(self)Check if the Sandbox has finished running.
Returns
None if the Sandbox is still running, otherwise the exit code.
exec
exec(self, *args, stdout=StreamType.PIPE, stderr=StreamType.PIPE, timeout=None,
workdir=None, env=None, secrets=None, text=True, bufsize=-1, pty=False,
_pty_info=None, pty_info=None)Execute a command in the Sandbox and return a ContainerProcess handle.
See the ContainerProcess docs for more information.
Parameters
-1 means unbuffered; 1 means line-buffered (only when text is True). (Default is -1)pty instead. pty will override _pty_info. pty instead. pty will override pty_info. Returns
A ContainerProcess handle for the running command (text or bytes depending on text).
Usage
process = sandbox.exec("bash", "-c", "for i in $(seq 1 3); do echo foo $i; sleep 0.1; done")
for line in process.stdout:
print(line)filesystem
filesystem: SandboxFilesystemNamespace for Sandbox filesystem APIs.
filesystem.copy_from_local
copy_from_local(self, local_path, remote_path)Copy a local file into the Sandbox.
remote_path must be an absolute path to a file in the Sandbox.
Parent directories for remote_path are created if needed.
The remote file is overwritten if it already exists.
Parameters
Raises
SandboxFilesystemNotADirectoryError: A parent path component ofremote_pathis not a directory.SandboxFilesystemIsADirectoryError:remote_pathpoints to a directory.SandboxFilesystemPermissionError: Write permission is denied in the Sandbox.SandboxFilesystemError: The command fails for any other reason.FileNotFoundError:local_pathdoes not exist.IsADirectoryError:local_pathis a directory.PermissionError: Readinglocal_pathis not permitted.
Usage
import tempfile
from pathlib import Path
local_path = Path(tempfile.mktemp())
local_path.write_text("Hello, world!\n")
sandbox.filesystem.copy_from_local(local_path, "/tmp/hello.txt")filesystem.copy_to_local
copy_to_local(self, remote_path, local_path)Copy a file from the Sandbox to a local path.
remote_path must be an absolute path to a file in the Sandbox.
Parent directories for local_path are created if needed.
The local file is overwritten if it already exists.
Raises
SandboxFilesystemNotFoundError: the remote path does not exist.SandboxFilesystemIsADirectoryError: the remote path points to a directory.SandboxFilesystemPermissionError: read permission is denied in the Sandbox.SandboxFilesystemError: the command fails for any other reason.IsADirectoryError:local_pathpoints to a directory.NotADirectoryError: a component of thelocal_pathparent is not a directory.PermissionError: writinglocal_pathis not permitted.
Usage
sandbox.filesystem.write_text("Hello, world!\n", "/tmp/hello.txt")
sandbox.filesystem.copy_to_local("/tmp/hello.txt", "/tmp/local-hello.txt")filesystem.list_files
list_files(self, remote_path)List files and directories in a Sandbox directory.
Parameters
Returns
A list of FileInfo objects describing each entry.
Raises
SandboxFilesystemNotFoundError: The path does not exist.SandboxFilesystemNotADirectoryError: The path is not a directory.SandboxFilesystemPermissionError: Read permission is denied.SandboxFilesystemError: The command fails for any other reason.
Usage
entries = sandbox.filesystem.list_files("/tmp")
for entry in entries:
print(entry.name, entry.type, entry.size)filesystem.make_directory
make_directory(self, remote_path, *, create_parents=True)Create a new directory in the Sandbox.
remote_path must be an absolute path in the Sandbox.
When create_parents is True (the default), any missing parent directories are created and the call is
idempotent (succeeds silently if the directory already exists). When create_parents is False, the
immediate parent directory must already exist and the path must not already exist.
Parameters
True, create missing parents and succeed if the directory already exists. (Default is True)Raises
SandboxFilesystemNotFoundError: The parent directory does not exist andcreate_parentsis false.SandboxFilesystemPathAlreadyExistsError: The path already exists.SandboxFilesystemNotADirectoryError: A path component is not a directory.SandboxFilesystemPermissionError: Creation is not permitted.InvalidError: The operation is not supported by the mount.SandboxFilesystemError: The command fails for any other reason.
Usage
sandbox.filesystem.make_directory("/tmp/a/b/c")filesystem.read_bytes
read_bytes(self, remote_path)Read a file from the Sandbox and return its contents as bytes.
remote_path must be an absolute path to a file in the Sandbox.
Parameters
Returns
Raw bytes read from the file.
Raises
SandboxFilesystemNotFoundError: The path does not exist.SandboxFilesystemIsADirectoryError: The path points to a directory.SandboxFilesystemPermissionError: Read permission is denied.SandboxFilesystemError: The command fails for any other reason.
Usage
sandbox.filesystem.write_bytes(b"Hello, world!\n", "/tmp/hello.bin")
contents = sandbox.filesystem.read_bytes("/tmp/hello.bin")
print(contents.decode("utf-8"))filesystem.read_text
read_text(self, remote_path)Read a file from the Sandbox and return its contents as a UTF-8 string.
remote_path must be an absolute path to a file in the Sandbox.
Parameters
Returns
File contents decoded as UTF-8.
Raises
SandboxFilesystemNotFoundError: The path does not exist.SandboxFilesystemIsADirectoryError: The path points to a directory.SandboxFilesystemPermissionError: Read permission is denied.SandboxFilesystemError: The command fails for any other reason.
Usage
sandbox.filesystem.write_text("Hello, world!\n", "/tmp/hello.txt")
contents = sandbox.filesystem.read_text("/tmp/hello.txt")
print(contents)filesystem.remove
remove(self, remote_path, *, recursive=False)Remove a file or directory in the Sandbox.
When remote_path is a directory and recursive is False (the
default), removes it only if it is empty. When recursive is True,
removes the directory and all its contents.
Recursive directory removal is not supported on all mounts.
In particular, CloudBucketMount does not support it. An InvalidError is raised in that case.
Parameters
True, remove the directory and all its contents. (Default is False)Raises
SandboxFilesystemNotFoundError: The remote path does not exist.SandboxFilesystemDirectoryNotEmptyError:recursiveisFalseand the directory is not empty.SandboxFilesystemPermissionError: Read permission is denied in the Sandbox.InvalidError: The operation is not supported by the mount.SandboxFilesystemError: The command fails for any other reason.
Usage
To remove a file:
sandbox.filesystem.write_bytes(b"Hello, world!\n", "/tmp/hello.bin")
sandbox.filesystem.remove("/tmp/hello.bin")To remove a directory and all its contents:
sandbox.filesystem.make_directory("/tmp/mydir/subdir")
sandbox.filesystem.remove("/tmp/mydir", recursive=True)filesystem.stat
stat(self, remote_path)Return metadata for a single file, directory, or symlink in the Sandbox.
remote_path must be an absolute path in the Sandbox. If remote_path is a symlink, the returned FileInfo object describes the symlink, not the target it points to.
Raises
SandboxFilesystemNotFoundError: the path does not exist.SandboxFilesystemNotADirectoryError: a non-leaf component of the path is not a directory.SandboxFilesystemPermissionError: a component of the path is not searchable.SandboxFilesystemError: the command fails for any other reason.
Usage
sandbox.filesystem.write_text("Hello, world!\n", "/tmp/hello.txt")
info = sandbox.filesystem.stat("/tmp/hello.txt")
print(info.size, info.permissions, info.modified_time)filesystem.watch
watch(self, remote_path, *, filter=None, recursive=False, timeout=None)Watch a path in the Sandbox for filesystem changes.
remote_path must be an absolute path in the Sandbox. If it points
to a file, events for that file are reported. If it points to a
directory, events for entries directly inside it are reported. Set recursive=True to also receive events for all nested subdirectories.
If remote_path is a symlink, it is followed and events reference
paths under the resolved target.
Yields FileWatchEvent objects as changes occur, until either timeout seconds elapse, the iterator is closed, or the Sandbox
is terminated.
Optionally restrict the kinds of events emitted to those included
in filter. The default filter None permits all event types.
timeout is in seconds. None means watch indefinitely. When timeout elapses, the iterator stops without raising an exception.
Raises
SandboxFilesystemNotFoundError:remote_pathdoes not exist.SandboxFilesystemPermissionError: watch access is denied.InvalidError: the filesystem atremote_pathdoes not support watching.SandboxFilesystemError: the command fails for any other reason.
Usage
for event in sandbox.filesystem.watch(
"/tmp/foo",
recursive=True,
filter=[FileWatchEventType.Create],
timeout=60,
):
if any(p.endswith(".done") for p in event.paths):
breakfilesystem.write_bytes
write_bytes(self, data, remote_path)Write binary content to a file in the Sandbox.
remote_path must be an absolute path to a file in the Sandbox.
Parent directories for remote_path are created if needed.
The remote file is overwritten if it already exists.
Parameters
Raises
TypeError:datais not bytes-like.SandboxFilesystemNotADirectoryError: A parent path component is not a directory.SandboxFilesystemIsADirectoryError:remote_pathpoints to a directory.SandboxFilesystemPermissionError: Write permission is denied.SandboxFilesystemError: The command fails for any other reason.
Usage
sandbox.filesystem.write_bytes(b"Hello, world!\n", "/tmp/hello.bin")filesystem.write_text
write_text(self, data, remote_path)Write UTF-8 text to a file in the Sandbox.
remote_path must be an absolute path to a file in the Sandbox.
Parent directories for remote_path are created if needed.
The remote file is overwritten if it already exists.
Parameters
Raises
TypeError:datais not a string.SandboxFilesystemNotADirectoryError: A parent path component is not a directory.SandboxFilesystemIsADirectoryError:remote_pathpoints to a directory.SandboxFilesystemPermissionError: Write permission is denied.SandboxFilesystemError: The command fails for any other reason.
Usage
sandbox.filesystem.write_text("Hello, world!\n", "/tmp/hello.txt")open
open(self, path, mode="r")[Alpha] Open a file in the Sandbox and return a FileIO handle.
Deprecated (2026-03-09): Use the Sandbox.filesystem APIs instead for improved reliability.
See the FileIO docs for more information.
Parameters
open conventions. (Default is "r")Returns
A FileIO handle for reading or writing the remote file.
Usage
sb = modal.Sandbox.create(app=sb_app)
f = sb.open("/test.txt", "w")
f.write("hello")
f.close()ls
ls(self, path)[Alpha] List the contents of a directory in the Sandbox.
Deprecated (2026-04-15): Use Sandbox.filesystem.list_files() instead for improved reliability.
Parameters
Returns
Entry names in the directory as a list of strings.
mkdir
mkdir(self, path, parents=False)[Alpha] Create a new directory in the Sandbox.
Deprecated (2026-04-15): Use Sandbox.filesystem.make_directory() instead for improved reliability.
rm
rm(self, path, recursive=False)[Alpha] Remove a file or directory in the Sandbox.
Deprecated (2026-04-15): Use Sandbox.filesystem.remove() instead for improved reliability.
watch
watch(self, path, filter=None, recursive=None, timeout=None)[Alpha] Watch a file or directory in the Sandbox for changes.
Deprecated (2026-05-08): Use Sandbox.filesystem.watch() instead for improved reliability.
Parameters
Returns
An async iterator of FileWatchEvent values.
stdout
stdout(self)StreamReader for the sandbox’s stdout stream.
Returns
Stream reader for sandbox stdout.
stderr
stderr(self)StreamReader for the Sandbox’s stderr stream.
Returns
Stream reader for sandbox stderr.
stdin
stdin(self)StreamWriter for the Sandbox’s stdin stream.
Returns
Stream writer for sandbox stdin.
returncode
returncode(self)Return code of the Sandbox process if it has finished running, else None.
Returns
Exit code when the sandbox process has completed, otherwise None.
list
list(*, app_id=None, tags=None, client=None)List all Sandboxes for the current Environment or App ID (if specified). If tags are specified, only Sandboxes that have at least those tags are returned.
Parameters
Client.from_env() when omitted. Returns
An async generator yielding Sandbox objects.