Windows Sandboxes
Windows virtual machine sandboxes, their capabilities, use cases, and architecture.
Windows sandboxes are Windows virtual machines (VMs). Each sandbox is a virtual machine, a microVM, that runs a full copy of Windows Server 2022 with a desktop on shared physical hardware. The hardware enforces the boundary and isolation between sandboxes.
| Term | Description |
|---|---|
| Base image | A prepared Windows Server 2022 disk that every Windows sandbox starts from. Windows is installed and configured before any sandbox boots from it. |
| Firmware | The program a computer runs before the operating system. Windows sandboxes use Unified Extensible Firmware Interface (UEFI) firmware. |
| Remote Desktop Protocol (RDP) | The Windows protocol for showing a desktop on another computer and sending it mouse and keyboard input. |
| PowerShell | The Windows command shell and scripting language. |
| Block snapshot | A saved copy of a Windows sandbox's disk that new Windows sandboxes can start from. |
Use cases
Windows sandboxes are used when the software, the test, or the task requires Windows.
- Computer-use agents on Windows: an agent operates Windows applications through screenshots, input events, and the accessibility tree, for Windows-only tasks.
- Windows-only software: programs, installers, and command-line tools that have no Linux version run in an isolated machine instead of on a shared Windows server.
- Build and test on Windows: code, scripts, and installers are built or tested on a clean Windows machine for each run, so results do not depend on leftover state.
- PowerShell and automation: PowerShell scripts and Windows administration tasks run against a real Windows installation before they reach production machines.
- Evaluation and reinforcement learning (RL): each test case or episode gets an identical Windows machine, started from the base image or from a prepared block snapshot.
- Remote Windows desktops: disposable desktops in the browser, with no local install. The Dashboard connects to the desktop over RDP through a Daytona gateway.
- Agents with the same API as Linux: the toolbox in a Windows sandbox serves the same API as the one in a Linux sandbox. SDK calls written for Linux sandboxes work against Windows sandboxes, and commands run in PowerShell.
- Prepared Windows environments: software installed once in a sandbox is saved with a block snapshot of its disk. New Windows sandboxes start from that disk instead of installing the software again.
Create a Windows sandbox
Create a Windows sandbox from the dashboard or programmatically.
- Go to Daytona Sandboxes ↗
- Click Create
- Select Windows sandbox
- Click Create
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{"image": "win2022"}'The following example sets the remaining fields:
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "win2022",
"name": "my-windows-sandbox",
"labels": { "team": "qa", "run": "42" },
"cpu": 2,
"mem_mib": 8192,
"scratch_mib": 40960,
"ports": [{ "vm_port": 8080 }, { "vm_port": 3389 }],
"env": { "LOG_LEVEL": "debug" },
"secrets": ["GITHUB_TOKEN"],
"persistent": true,
"spot": false,
"region": "us",
"lifecycle": {
"idle_timeout_secs": 3600,
"on_idle_timeout": "stop",
"timeout_secs": 86400,
"on_timeout": "delete"
},
"idempotency_key": "run-42-create"
}'| Field | Type | Description |
|---|---|---|
image | string | Sets the Windows image by name or ID. The image is a platform base image, such as win2022, or a block snapshot captured from a Windows sandbox in the project. This field is required. |
name | string | Sets the display name. If omitted, a name is generated. |
labels | object | Attaches key-value metadata to the sandbox. |
cpu | number | Sets the guaranteed CPU cores as a float. The value is raised to at least one core per 4 GiB of guaranteed memory. The default is 0.125. |
vcpus | integer | Sets an integer CPU request. It applies only if cpu is absent. The default is 2. |
mem_mib | integer | Sets the guaranteed memory in MiB. The default is 1024. |
scratch_mib | integer | Sets the guaranteed writable disk in MiB. The default is 512. |
ports | array | Forwards inbound ports to the sandbox. |
env | object | Sets environment variables inside the sandbox. |
secrets | array | Attaches project secrets by name. The sandbox sees each secret as an opaque placeholder. Attaching secrets needs an API key with read:secrets in addition to write:sandboxes. |
persistent | boolean | Adds a durable write layer, which enables stop and start. The default is false. |
spot | boolean | Runs the sandbox on discounted capacity that can be reclaimed. A reclaimed persistent Windows sandbox is stopped, not paused. The default is false. |
region | string | Sets the region or global region slug. The default is the project default. |
lifecycle | object | Sets the lifecycle policy with timeout_secs and on_timeout, and idle_timeout_secs and on_idle_timeout. Each action is stop or delete, and stop needs persistent. By default, there is no idle timeout, and the wall-clock timeout uses the organization or platform default, if one is enabled. |
idempotency_key | string | Makes a retried create return the same sandbox. You can also send it as the Idempotency-Key header. |
The response has the following fields:
| Field | Description |
|---|---|
status | The status is often pending, because the server holds the request for at most 3 seconds by default. Poll GET /sandboxes/{sandboxId}?wait=running until the sandbox is running. |
Desktop and remote access
Cloud Hypervisor provides no graphics card, so Windows has no physical screen to draw on. RDP does not need one: Windows renders an RDP session in memory and sends it to the client. The Desktop tab in the Daytona Dashboard connects to the sandbox over RDP through a Daytona gateway and shows the desktop in the browser.
The base image does not log a user in on its own. A desktop session exists only while someone is connected over RDP. This has two effects:
- An idle sandbox spends no memory or processor time on a desktop nobody sees
- Computer use works while a desktop session is open. The computer-use add-on attaches to that session and reconnects when the session changes. With no session, computer-use requests return an error that tells you to open the desktop
SSH connects to the base image's OpenSSH server through the same gateway as Linux.
Lifecycle
Every Windows sandbox moves through a lifecycle. A Windows sandbox can have several different states. Each state reflects the status of your sandbox. A Windows sandbox transitions between states in response to user actions, or automatically when one of its timeouts elapses.
| Feature | Persistent | Ephemeral |
|---|---|---|
| Stop and start | ✓ | ✗ |
| Pause and resume | ✗ | ✗ |
| Fork | ✗ | ✗ |
| Delete | ✓ | ✓ |
| Filesystem persistence | ✓ | ✗ |
| Memory persistence | ✗ | ✗ |
| Memory snapshot | ✗ | ✗ |
| Filesystem snapshot | ✓ block snapshot | ✓ block snapshot |
| Spot (Preemption) | ✓ | ✓ |
| Network policy | ✗ | ✗ |
| Desktop | ✓ RDP | ✓ RDP |
Every Windows sandbox supports wait for state, delete, timeouts, and lifecycle policy updates. Stop and start, and auto-stop require a persistent sandbox. A persistent Windows sandbox keeps its disk across stop and start and across host failure. Memory and running processes are cleared on every stop. Windows sandboxes do not support pause, resume, or fork. An ephemeral Windows sandbox keeps its disk and memory until it is deleted.
| State | Description |
|---|---|
queued | The create request is recorded and waits to be published for placement. |
pending | The create request is accepted and the sandbox is queued for placement. |
assigned | The sandbox is placed on a host. A start also re-enters this state. |
booting | Windows is booting from UEFI firmware and will be ready to use. |
running | The sandbox is running and ready to accept requests. |
stopping | Windows is shutting down and the sandbox no longer accepts requests. |
stopped | The sandbox is stopped. Compute is released and the disk is kept on network storage. |
deleting | The sandbox is being deleted. |
deleted | The sandbox and its disk are removed. |
failed | The sandbox could not boot or hit an unrecoverable error. |
lost | The host running an ephemeral sandbox was lost. A persistent sandbox on a lost host becomes stopped instead. |
| Initial state | Target state | Trigger |
|---|---|---|
queued | pending | The create request is published for placement. |
pending | assigned | The sandbox is placed on a host. |
assigned | booting | The host attaches the disk and Windows boots from UEFI firmware. |
booting | running | The sandbox daemon answers, the sandbox's secrets are delivered, and the sandbox accepts requests. |
running | stopping | A stop is requested on a persistent sandbox, or the platform reclaims a persistent spot sandbox. |
stopping | stopped | Windows shuts down. The disk is kept and memory state is cleared. |
stopped | assigned | A start is requested and the sandbox is placed again, possibly on different hardware. |
| any state | deleting | A delete is requested, or the platform reclaims an ephemeral spot sandbox. |
deleting | deleted | The sandbox is removed and its resources are released. |
| any active state | failed | The sandbox fails to boot or hits an unrecoverable error. |
running | stopped | The host running a persistent sandbox is lost. |
running | lost | The host running an ephemeral sandbox is lost. |
Wait for state
Wait until a Windows sandbox reaches a target state. The wait stops early when the sandbox reaches a state from which the target is no longer reachable, such as failed or deleted. The SDKs use their own state names, so the SDK started state corresponds to the running state in the CLI and API. A Windows sandbox never enters the pausing or paused states.
# Block until the sandbox is started; returns the sandbox
sandbox.wait(until="started", timeout=60)
# Block until the sandbox is stopped
sandbox.wait_for_state(["stopped"], timeout=60)| Parameter | Type | Description |
|---|---|---|
until | str | Sets the one state that wait() waits for. wait_for_state() takes a list and returns on any of its states. The default is "started". |
timeout | float | Sets the wait limit in seconds. None or 0 waits without a limit. When the timeout elapses, both methods raise RequestTimeoutError. The default is 60 for wait() and None for wait_for_state(). |
Stop / start
Stop and start a persistent Windows sandbox. Stopping shuts Windows down cleanly and keeps the disk. Memory state is cleared. While a stop is in progress, the sandbox is in the stopping state and does not accept new requests. Starting boots Windows from the preserved disk, possibly on different hardware. Daytona also stops a persistent spot Windows sandbox when it reclaims the capacity.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
# Shut Windows down cleanly; the disk is kept
sandbox.stop()
sandbox.wait_for_state(["stopped"], timeout=60)
# Boot Windows from the preserved disk
sandbox.start()Delete
Delete a Windows sandbox to tear down its virtual machine. Deletion works in any state, and the call returns once teardown starts. The sandbox moves from deleting to deleted when the teardown finishes. Daytona discards the sandbox's disk and memory, including the disk of a persistent sandbox. Block snapshots captured from the sandbox remain.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
sandbox.delete()Timeouts
Daytona stops or deletes a Windows sandbox automatically when one of its two timers elapses. Each timer pairs an interval in seconds with the action it fires. Set both timers at create in the lifecycle object, and change them later through update lifecycle policy.
| Timer | Purpose | Fires after | Default |
|---|---|---|---|
| Timeout | Cap how long a sandbox runs | The sandbox has been running for the interval, active or not | Project or platform default |
| Idle timeout | Stop or delete a sandbox that is not in use | The sandbox has had no activity for the interval | Project default, or off |
The valid actions depend on whether the sandbox is persistent and apply to both timers. Delete is valid for every Windows sandbox:
| Action | Ephemeral (default) | Persistent |
|---|---|---|
| Stop | ✗ | ✓ |
| Pause | ✗ | ✗ |
| Delete | ✓ | ✓ |
Auto-stop and auto-delete are not separate settings. Each one is the idle timeout with the matching action. The pause action and wake on request are not available for Windows sandboxes.
Timeout
The timeout is a wall-clock budget. It starts when the sandbox is created and re-arms with the full budget every time the sandbox enters running on start. Activity does not extend it. A delete timeout fires in any state. A stop timeout fires only while the sandbox is running. Once set, the timeout cannot be cleared.
When the timeout is omitted at create, Daytona applies the project's lifecycle defaults. A project default that pauses a persistent sandbox stops a persistent Windows sandbox instead. Without a project default, Daytona applies the platform default timeout of 300 seconds, if the platform default is enabled. An explicit timeout must not exceed the organization maximum, 86,400 seconds (24 hours) unless the organization sets a different maximum.
When the action is omitted, it defaults to stop for persistent Windows sandboxes and delete for ephemeral Windows sandboxes.
# Delete the sandbox 2 hours after it last entered running
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "win2022",
"lifecycle": { "timeout_secs": 7200, "on_timeout": "delete" }
}'Idle timeout
The idle timeout fires after the sandbox has had no activity for the interval. Activity is any request through the toolbox API, preview URLs, and SSH, a toolbox command that is still running, an open Remote Desktop (RDP) session through the Desktop gateway, and any lifecycle operation on the sandbox. The idle timeout is off by default unless the project sets one, has a minimum of 60 seconds, and requires an action. An idle stop fires only while the sandbox is running. The action fires within about 2 minutes after the interval elapses.
Auto-stop
Stop a persistent Windows sandbox after a period of inactivity. Stopping shuts Windows down cleanly and keeps the disk.
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "win2022",
"persistent": true,
"lifecycle": { "idle_timeout_secs": 900, "on_idle_timeout": "stop" }
}'Auto-delete
Delete a Windows sandbox after a period of inactivity.
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "win2022",
"lifecycle": { "idle_timeout_secs": 3600, "on_idle_timeout": "delete" }
}'Reset the idle timer
Reset the idle timer of a Windows sandbox to keep it alive while it does work that Daytona does not count as activity. The reset counts as activity, so the idle countdown restarts from now. The timeout is not affected.
The reset succeeds in any state, whether or not an idle timeout is set. It never moves the timer backwards: when newer activity arrives at the same time, the newer activity wins.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
lifecycle = sandbox.reset_idle_timer()
print(lifecycle.idle_timeout_at)Update lifecycle policy
Update the timeouts of an existing Windows sandbox. Omitted fields keep their current values. The new actions must be valid for the sandbox, as listed in timeouts.
from daytona import Daytona
from daytona.v2 import DISABLED
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
# Stop the sandbox after 30 minutes without activity; omitted fields keep their current value
lifecycle = sandbox.set_lifecycle(idle_timeout_secs=1800, on_idle_timeout="stop")
print(lifecycle.idle_timeout_secs, lifecycle.on_idle_timeout)
# Re-anchor the timeout to 1 hour from now
lifecycle = sandbox.set_lifecycle(timeout_secs=3600)
print(lifecycle.timeout_at)
# Clear the idle timeout
lifecycle = sandbox.set_lifecycle(idle_timeout_secs=DISABLED)Filesystem persistence
Filesystem persistence keeps the contents of a sandbox's disk: installed programs, cloned repositories, build artifacts, and the files the sandbox writes. A sandbox with a preserved disk starts with its environment intact, with nothing to reinstall or rebuild.
Windows sandboxes are ephemeral by default. An ephemeral Windows sandbox keeps its writable disk on the host. Deleting the sandbox discards the disk, and a host failure loses the sandbox. A persistent Windows sandbox keeps its writable disk on network storage that any capable host in the region can attach. Stop shuts Windows down and keeps the disk, and start boots Windows from the disk again, possibly on another host. A host failure leaves a persistent sandbox stopped instead of lost.
from daytona import Daytona
daytona = Daytona()
# A persistent Windows sandbox, created through the API with "persistent": true
sandbox = daytona.v2.get("{sandboxId}")
# Write state to the disk
sandbox.process.run(r"Set-Content -Path C:\setup.log -Value done")
# Stop shuts Windows down; the disk stays on network storage
sandbox.stop()
sandbox.wait_for_state(["stopped"], timeout=60)
# Start boots Windows from the preserved disk, possibly on another host
sandbox.start()
response = sandbox.process.run(r"Get-Content -Path C:\setup.log")
print(response.stdout) # doneBlock snapshot
A block snapshot saves the disk of a running Windows sandbox as an image. The sandbox keeps running, and new Windows sandboxes start from the block snapshot with the captured disk. A block snapshot holds no processes or memory. Ephemeral and persistent Windows sandboxes can both be captured.
The capture runs in the background: the block snapshot starts as pending and becomes ready when the capture finishes. Pass a block snapshot's name or ID as image to create a Windows sandbox from it.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
# Capture the disk; the sandbox keeps running
image = sandbox.snapshot_filesystem(name="my-win-image")
# Wait until the block snapshot is ready
while image.status not in ("ready", "failed"):
image = daytona.v2.images.get(image.id, wait="ready")
if image.status == "failed":
raise RuntimeError(image.error)| Parameter | Type | Description |
|---|---|---|
name | str | Sets the image name, which must be unique in the project. The default is None, which makes the image anonymous. |
Spot
Windows sandboxes run on reserved capacity by default. A spot Windows sandbox runs on discounted capacity that Daytona can reclaim at any time to free resources for full-price sandboxes. Spot multiplies the CPU, memory, and disk price by 0.7. Apart from price and reclaim, a spot Windows sandbox supports the same images, resources, and lifecycle operations as any other Windows sandbox.
A reclaim is immediate, with no advance notice and no grace period. The outcome depends on whether the sandbox is persistent:
| Sandbox | On reclaim |
|---|---|
| Ephemeral | Moves to deleting, then deleted, with its disk. |
| Persistent | Moves to stopping, then stopped, with the disk kept and memory cleared. |
Daytona does not bring a reclaimed sandbox back on its own. A reclaimed sandbox carries the reclaim time in spot_evicted_at until it is started. To continue, start the stopped sandbox. The sandbox stays spot and can be reclaimed again.
from daytona import Daytona
daytona = Daytona()
# A persistent spot Windows sandbox, created through the API
sandbox = daytona.v2.get("{sandboxId}")
# spot_evicted_at is None unless Daytona reclaimed the sandbox
if sandbox.spot_evicted_at:
# Start boots Windows from the preserved disk
sandbox.start()