Skip to main content
Sandboxes are interactive, stateful containers that allow you to execute commands and interact with a remote environment.

Creating sandboxes

Create

Creates a new Sandbox in the specified App with the given Image.
app, _ := mc.Apps.FromName(ctx, "my-app", &modal.AppFromNameParams{
    CreateIfMissing: true,
})
image := mc.Images.FromRegistry("python:3.11", nil)

sb, err := mc.Sandboxes.Create(ctx, app, image, &modal.SandboxCreateParams{
    CPU:       2.0,
    MemoryMiB: 2048,
    Timeout:   10 * time.Minute,
})
if err != nil {
    // Handle error
}
defer sb.Terminate(ctx, nil)
ctx
context.Context
required
Context for the operation
app
*App
required
The App to create the Sandbox in
image
*Image
required
The Image to use for the Sandbox
params
*SandboxCreateParams
Sandbox configuration options
CPU
float64
CPU request in fractional cores
CPULimit
float64
Hard CPU limit in fractional cores
MemoryMiB
int
Memory request in MiB
MemoryLimitMiB
int
Hard memory limit in MiB
GPU
string
GPU configuration (e.g., “T4”, “A100:2”)
Timeout
time.Duration
Maximum lifetime. Defaults to 5 minutes.
IdleTimeout
time.Duration
Idle timeout before termination
Workdir
string
Working directory (absolute path)
Command
[]string
Command to run on startup
Env
map[string]string
Environment variables
Secrets
[]*Secret
Secrets to inject
Volumes
map[string]*Volume
Volume mount points
CloudBucketMounts
map[string]*CloudBucketMount
Cloud bucket mount points
PTY
bool
Enable PTY (pseudo-terminal)
EncryptedPorts
[]int
List of encrypted ports to tunnel (TLS)
H2Ports
[]int
List of HTTP/2 ports to tunnel
UnencryptedPorts
[]int
List of unencrypted ports to tunnel
BlockNetwork
bool
Block all network access
CIDRAllowlist
[]string
Allowed CIDR ranges (cannot be used with BlockNetwork)
Cloud
string
Cloud provider
Regions
[]string
Preferred regions
Verbose
bool
Enable verbose logging
Proxy
*Proxy
Modal Proxy to use
Name
string
Optional name (unique within the App)
CustomDomain
string
Custom domain for connections (Enterprise only)
Returns:
  • *Sandbox - The created Sandbox
  • error - Error if creation fails

FromID

References a running Sandbox by its ID.
sb, err := mc.Sandboxes.FromID(ctx, "sb-123abc")
if err != nil {
    // Handle error
}
ctx
context.Context
required
Context for the operation
sandboxID
string
required
The Sandbox ID
Returns:
  • *Sandbox - The Sandbox instance
  • error - NotFoundError if the Sandbox doesn’t exist

FromName

References a running Sandbox by name.
sb, err := mc.Sandboxes.FromName(ctx, "my-app", "my-sandbox", nil)
if err != nil {
    // Handle error
}
ctx
context.Context
required
Context for the operation
appName
string
required
The App name
name
string
required
The Sandbox name
params
*SandboxFromNameParams
Optional parameters
Environment
string
Environment name
Returns:
  • *Sandbox - The Sandbox instance
  • error - NotFoundError if the Sandbox doesn’t exist

List

Lists Sandboxes, optionally filtered by App or tags.
iter, err := mc.Sandboxes.List(ctx, &modal.SandboxListParams{
    AppID: "ap-123abc",
    Tags:  map[string]string{"env": "prod"},
})
if err != nil {
    // Handle error
}

for sb, err := range iter {
    if err != nil {
        // Handle error
        break
    }
    fmt.Printf("Sandbox: %s\n", sb.SandboxID)
}
ctx
context.Context
required
Context for the operation
params
*SandboxListParams
Filtering options
AppID
string
Filter by App ID
Tags
map[string]string
Filter by tags (must match all)
Environment
string
Environment name
Returns:
  • iter.Seq2[*Sandbox, error] - Iterator over Sandboxes
  • error - Error if the request fails

Sandbox methods

Exec

Executes a command in the Sandbox and returns a ContainerProcess.
p, err := sb.Exec(ctx, []string{"python", "script.py"}, &modal.SandboxExecParams{
    Workdir: "/app",
    Env:     map[string]string{"DEBUG": "1"},
})
if err != nil {
    // Handle error
}

stdout, _ := io.ReadAll(p.Stdout)
fmt.Printf("Output: %s\n", stdout)

exitCode, _ := p.Wait(ctx)
fmt.Printf("Exit code: %d\n", exitCode)
ctx
context.Context
required
Context for the operation
command
[]string
required
Command and arguments to execute
params
*SandboxExecParams
Execution options
Stdout
StdioBehavior
“pipe” or “ignore” (default: “pipe”)
Stderr
StdioBehavior
“pipe” or “ignore” (default: “pipe”)
Workdir
string
Working directory for the command
Timeout
time.Duration
Execution timeout
Env
map[string]string
Environment variables
Secrets
[]*Secret
Secrets to inject
PTY
bool
Enable PTY
Returns:
  • *ContainerProcess - Handle to the running process
    • Stdin (io.WriteCloser) - Standard input
    • Stdout (io.ReadCloser) - Standard output
    • Stderr (io.ReadCloser) - Standard error
    • Wait(ctx) (int, error) - Wait for process to complete
  • error - Error if execution fails

Terminate

Stops the Sandbox.
exitCode, err := sb.Terminate(ctx, &modal.SandboxTerminateParams{
    Wait: true,
})
if err != nil {
    // Handle error
}
ctx
context.Context
required
Context for the operation
params
*SandboxTerminateParams
Termination options
Wait
bool
Wait for the Sandbox to exit and return exit code
Returns:
  • int - Exit code (if Wait is true)
  • error - Error if termination fails

Wait

Blocks until the Sandbox exits.
exitCode, err := sb.Wait(ctx)
fmt.Printf("Sandbox exited with code: %d\n", exitCode)
ctx
context.Context
required
Context for the operation
Returns:
  • int - Exit code
  • error - Error if waiting fails

Poll

Checks if the Sandbox has finished running.
exitCode, err := sb.Poll(ctx)
if exitCode == nil {
    fmt.Println("Still running")
} else {
    fmt.Printf("Exited with code: %d\n", *exitCode)
}
ctx
context.Context
required
Context for the operation
Returns:
  • *int - Exit code if finished, nil if still running
  • error - Error if the request fails

Tunnels

Gets tunnel metadata for the Sandbox’s exposed ports.
tunnels, err := sb.Tunnels(ctx, 30*time.Second)
if err != nil {
    // Handle error
}

for port, tunnel := range tunnels {
    fmt.Printf("Port %d: %s\n", port, tunnel.URL())
}
ctx
context.Context
required
Context for the operation
timeout
time.Duration
required
Timeout to wait for tunnels to be ready
Returns:
  • map[int]*Tunnel - Map of container port to Tunnel
    • Host (string) - Public hostname
    • Port (int) - Public port
    • URL() (string) - HTTPS URL
    • TLSSocket() (string, int) - TLS socket
    • TCPSocket() (string, int, error) - TCP socket
  • error - SandboxTimeoutError if tunnels aren’t ready

SnapshotFilesystem

Snapshots the Sandbox’s filesystem to an Image.
image, err := sb.SnapshotFilesystem(ctx, 5*time.Minute)
if err != nil {
    // Handle error
}
fmt.Printf("Snapshot image: %s\n", image.ImageID)
ctx
context.Context
required
Context for the operation
timeout
time.Duration
required
Timeout for the snapshot operation
Returns:
  • *Image - The snapshot Image
  • error - Error if snapshot fails

Detach

Disconnects from the Sandbox, cleaning up local resources.
err := sb.Detach()
if err != nil {
    // Handle error
}
Returns:
  • error - Error if detachment fails

Example usage

package main

import (
    "context"
    "fmt"
    "io"
    "time"

    "github.com/modal-labs/modal-client/go"
)

func main() {
    ctx := context.Background()
    mc, _ := modal.NewClient()
    defer mc.Close()

    app, _ := mc.Apps.FromName(ctx, "my-app", &modal.AppFromNameParams{
        CreateIfMissing: true,
    })
    image := mc.Images.FromRegistry("python:3.11", nil)

    // Create a Sandbox
    sb, err := mc.Sandboxes.Create(ctx, app, image, &modal.SandboxCreateParams{
        Timeout: 10 * time.Minute,
    })
    if err != nil {
        panic(err)
    }
    defer sb.Terminate(ctx, nil)

    // Execute a command
    p, _ := sb.Exec(ctx, []string{"python", "-c", "print('Hello from Modal!')"}, nil)
    stdout, _ := io.ReadAll(p.Stdout)
    fmt.Printf("Output: %s\n", stdout)

    exitCode, _ := p.Wait(ctx)
    fmt.Printf("Exit code: %d\n", exitCode)
}

Build docs developers (and LLMs) love