Tutorial: Work with sandboxes using the Python SDK¶
The quickstart creates one sandbox inside a with block and terminates it on exit. That covers a single piece of work in a single process.
This tutorial covers the four things you need beyond that: sandboxes that outlive a with block, tasks that outlive the driver process, querying Snowflake from inside the container, and running many sandboxes at once. Each step is independent, so you can read only the one you need.
Prerequisites¶
- The
snowflake-sandbox-pythonSDK installed and a Snowflake connection configured. See Cortex Sandboxes quickstart. - Run the examples from a local terminal, not from inside a Snowflake Workspace. A driver running in a Workspace creates a sandbox that does not inherit the credentials
snowflake.connectorneeds to connect back to Snowflake from inside the container.
Save each example to a file and run it with python main.py.
Step 1: Run longer-lived work with a named sandbox¶
For work that should persist and be reconnected to later, give the sandbox a name and reconnect by that name:
The name is the identity you reconnect with. Sandbox.connect() takes a name, not an ID, and a name is unique per owner.
A named sandbox created outside a with block keeps running until something terminates it. It does not bill compute for the whole of that time: the platform auto-suspends a sandbox that has been idle and resumes it on next use, so an idle named sandbox stops consuming compute without being deleted. The default idle window is 10 minutes. Pass idle_suspend= to Sandbox.create() to choose a different one, as a datetime.timedelta or a duration string such as "30m", down to a minimum of one minute.
Suspension is not deletion, though. A suspended sandbox still exists, still counts against your live-sandbox cap, and always resumes as a fresh container that has lost /tmp and every running process. Call terminate() when the work is done, as the example does.
For listing what is running, streaming logs from it, and handling a cold restart, see Tutorial: Reconnect to a running sandbox.
Step 2: Run a detached task and wait for it¶
For work that should run to completion and outlive this driver process, start a sandbox with a command and poll its result with wait(). Give it a name and reattach with Sandbox.connect() to check on it later from any process:
The task runs to completion on its own; the driver reattaches and waits, then prints succeeded 0. wait() returns a RunResult whose status is "succeeded", "failed", or "timed_out".
A reattached handle reports the outcome but not the returned value: result.result is populated only on the handle that created the run, so on a handle from Sandbox.connect() it is always None. To collect a return value, either keep the handle create() returned and call wait() on it, or have the task write its output somewhere durable, such as a Snowflake table or a stage, and read it from there.
Step 3: Query Snowflake from inside the sandbox¶
Sandboxes run with your own session identity. Code inside the sandbox can query Snowflake without any credential configuration, because the platform provides the credential and get_snowflake_connection() resolves it:
The script connects from inside the sandbox using your injected session identity and prints the user and role the sandbox runs as, for example:
Your Snowflake governance policies, including row-level security and column masking, apply to what the script can read, exactly as they would for any query you run directly. See Cortex Sandboxes concepts and security and Tutorial: Governance enforcement in a sandbox.
get_snowflake_connection() is the recommended path for in-sandbox code, production included. It handles the host format, the role, a default login timeout, and the platform’s egress-proxy CA, all of which hand-rolled connector code commonly gets wrong. For what it resolves and for the cases where you need to control the connection yourself, see Connect to Snowflake from the SDK.
Step 4: Fan out across sandboxes in parallel¶
Each sandbox is independent, so you can run work across many sandboxes at once using threads:
The five sandboxes run in parallel, so the whole fan-out finishes in roughly the time of a single run and prints 0 through 4.
This example omits image, so each sandbox uses the server’s default base image. To select a specific image, pass image= to Sandbox.create().
Fan out without holding a thread per sandbox¶
The pattern above holds a thread for each sandbox’s whole lifetime, because Sandbox.create() blocks until the container is live. For a larger fan-out, wait=False returns immediately and lets you fire every create first, then wait for readiness:
wait_until_ready() is a no-op on a sandbox that is already ready. It raises SandboxNotReadyError if the timeout expires first, and SandboxTransportError if the server reports a create failure.
Important
Terminate what you create. Nothing expires a sandbox on its own: the platform suspends an idle one so it stops consuming compute, but never removes it, and a suspended sandbox still counts against your quota of 100 live sandboxes per identity. A fan-out like the one above strands ten containers per run if you skip the teardown, and once you pass the cap, every Sandbox.create() is refused. The with form handles this for you; wait=False does not, which is why it needs the ExitStack.
What this demonstrates¶
- A name is an identity, not a label. It is what
Sandbox.connect()resolves, it is unique per owner, and it is what makes a sandbox outlive the process that created it. - Idle suspension is not cleanup. It stops compute; it does not release quota or free the container. Termination is explicit, always.
- Identity is supplied, not configured. Code inside the sandbox reaches Snowflake as you, with your governance applied, and no credential is placed in the container.
- Parallelism is per-sandbox. Isolation does not weaken as you fan out, but quota is shared, so teardown matters more the wider you go.
Going further¶
- To list running sandboxes, stream logs, and handle cold restarts, see Tutorial: Reconnect to a running sandbox.
- To apply the fan-out pattern to real work, see Tutorial: Run Cortex batch inference over a Snowflake table.
- To give a sandbox access to an external API without placing a credential in it, see Tutorial: Give a sandbox secure access to an external API.
- For the full API surface, see the Cortex Sandboxes SDK reference.