Skip to content
Guides · Starters

How Do I Run Deno in a Cloud Sandbox?

Updated October 27, 2026 .md

Short answer: Deno is not in the sandbox image. The official install script added Deno 2.9.8 in 1.9 seconds. Its caches live in ~/.cache/deno on the sandbox disk, so a named snapshot cut a cold dependency install plus type check of the Fresh repo from about 20 seconds to about 6.

We ran every command on this page on prod on 2026-10-27 in eu-central, on small sandboxes (2 vCPU, 4 GB). The project is denoland/fresh, Deno's web framework, at commit 86d6cde. It is a Deno workspace with JSR and npm dependencies, a deno.lock, 384 type-checked files and the source of the Fresh website.

Results#

Step Time on small
Install Deno 2.9.8 with the official script 1.9 s
deno install, empty DENO_DIR (2 sandboxes) 5.3, 3.0 s
deno install, warm DENO_DIR, no node_modules or vendor 2.2 s
deno install, nothing to do 0.14 s
deno task check:types, empty check cache (3 runs) 14.5, 15.0, 15.3 s
deno task check:types, warm (3 runs) 5.8, 5.9, 6.1 s
Unit tests in packages/fresh/src, empty check cache / warm 13.9 to 16.1 s / 11.3 to 12.0 s
Full deno task test (2 runs) 290, 285 s
deno task build-www (Vite build of the Fresh site) 9.9, 10.2 s
deno compile for one target 0.45 to 1.7 s
From the named snapshot: deno install / check:types / unit tests 0.33 s / 6.1 s / 12.0 s

The lesson: Deno's caches help the steps before your code runs. Dependency install and type checking got about three times faster. The full test suite took the same 4 minutes 45 seconds with a warm cache, because its time goes into running browser and server tests, not into loading modules.

1. Install Deno#

A new sandbox has Node, Bun, Go and Rust, but no Deno (full inventory). unzip and curl, which the script needs, are there. The current release on 2026-10-27, per https://dl.deno.land/release-latest.txt, was v2.9.8. Pin it so every sandbox gets the same build, using the official install script:

sbx new --name deno-1 --type small
sbx exec sb_sqzi8b8j3p --timeout 300 bash -lc "curl -fsSL https://deno.land/install.sh | sh -s -- -y v2.9.8 && deno --version && deno info"
Deno was installed successfully to /home/user/.deno/bin/deno
…
info: backing '/home/user/.profile' up to '/home/user/.deno/.shellRcBackups/.profile.bak'
info: backing '/home/user/.bashrc' up to '/home/user/.deno/.shellRcBackups/.bashrc.bak'

Deno was added to the PATH.
…
deno 2.9.8 (stable, release, x86_64-unknown-linux-gnu)
v8 15.0.245.2-rusty
typescript 6.0.3
DENO_DIR location: /home/user/.cache/deno
Remote modules cache: /home/user/.cache/deno/remote
npm modules cache: /home/user/.cache/deno/npm
…

It took 1.9 seconds. -y skips the script's prompts and adds . "$HOME/.deno/env" to .bashrc and .profile, so plain sbx exec and SSH sessions find deno too. Without a version argument the script installs whatever is latest that day.

Everything Deno keeps is under /home/user: the binary in ~/.deno, and modules, npm packages and its SQLite caches in ~/.cache/deno. All of it survives sbx stop and goes into a named snapshot.

2. Install dependencies#

sbx exec sb_sqzi8b8j3p --timeout 600 bash -lc "git clone -q https://github.com/denoland/fresh && cd fresh && git checkout -q 86d6cdeb331a && deno install"

Fresh's deno.json sets "vendor": true and "nodeModulesDir": "manual". So deno install fills three places: ~/.cache/deno (310 MB after the first install), a local vendor/ with the JSR modules (19 MB) and node_modules/ (23 MB). The last two are git-ignored, but they are on disk, so a snapshot keeps them.

The cold install took 5.3 seconds in one sandbox and 3.0 in another. With DENO_DIR warm and vendor/ and node_modules/ deleted, it took 2.2 seconds; with nothing to do, 0.14. deno install also printed the npm deprecation warnings for two transitive packages; they don't fail the install.

3. Type check and test, cold and warm#

Deno type checks TypeScript before deno test runs it and when you call deno check. It stores the results in SQLite files in DENO_DIR (check_cache_v2, fast_check_cache_v2 and others). We timed Fresh's own task, which checks the whole workspace, after deleting those files and again warm:

cd ~/fresh
rm -f ~/.cache/deno/check_cache_v2* ~/.cache/deno/fast_check_cache_v2*; rm -rf ~/.cache/deno/gen
time deno task check:types   # 384 files
time deno task check:types
== check:types, no check cache (1)
14.539 s
== check:types, warm (1)
5.805 s
== check:types, no check cache (2)
14.987 s
== check:types, warm (2)
5.932 s

The unit tests in packages/fresh/src gave 316 passed, 0 failed, 4 ignored, in 13.9 to 16.1 seconds with an empty check cache and 11.3 to 12.0 seconds warm.

One detail cost us a snapshot. The check cache holds results for the module graphs you actually checked. deno test checks test files too, so its results don't cover deno check, and the other way round: right after a warm check:types, the unit tests still took 16.1 seconds. Our first snapshot was saved after a test run only, and check:types in the sandbox started from it took 15.4 seconds, a cold check. Before you save, run each command you will run later.

The full suite, deno task test (deno test -A --parallel), took 290 seconds, and 285 with every cache warm. That is past the 30-second default of sbx exec, so we put the run in a script (cd ~/fresh && NO_COLOR=1 deno task test > ~/test1.log 2>&1, timed with bash time), started it in the background and read the log:

sbx exec sb_sqzi8b8j3p --detach "bash -l b2.sh > b2.log 2>&1"
sbx exec sb_sqzi8b8j3p "tail -3 test1.log"
FAILED | 624 passed (14 steps) | 1 failed | 13 ignored (4m38s)

error: Test failed

The one failure, init - fmt, lint, and type check project, came from Deno itself: in the project the test generates, deno fmt --check reported Found 1 not formatted file in 12 files. It failed the same way on both runs. The suite also starts real browsers through the Astral library; after the run, ~/.cache/astral held a 503 MB Chrome build next to the image's own /usr/bin/google-chrome. It is under /home/user too, so the snapshot keeps it.

4. Use Deno permissions inside the sandbox#

The sandbox is the boundary between your code and your machine. Deno adds a second one inside it: a script gets no network, file, environment or subprocess access unless you grant it (Deno security). That is useful when an agent runs code it wrote. This script fetches a URL and reads HOME:

// fetch.ts
const url = Deno.args[0] ?? "https://jsr.io/@std/http/meta.json";
const res = await fetch(url);
console.log(res.status, url);
console.log("HOME is", Deno.env.get("HOME"));
deno run fetch.ts
deno run --allow-net=jsr.io --allow-env=HOME fetch.ts https://example.com
deno run --allow-net=jsr.io --allow-env=HOME fetch.ts
error: Uncaught (in promise) NotCapable: Requires net access to "jsr.io:443", run again with the --allow-net flag
error: Uncaught (in promise) NotCapable: Requires net access to "example.com:443", run again with the --allow-net flag
200 https://jsr.io/@std/http/meta.json
HOME is /home/user

Each denied call exited with code 1. Under sbx exec there is no terminal, so Deno fails instead of prompting.

Environment access matters here because a sandbox sets SANDBOXER_TOKEN for code that calls the Sandboxer API about its own sandbox (environment variables in a sandbox). A script that reads HOME and SANDBOXER_TOKEN, run two ways:

--- allow-env=HOME
HOME readable (10 chars)
SANDBOXER_TOKEN denied: NotCapable
--- -A
HOME readable (10 chars)
SANDBOXER_TOKEN readable (48 chars)

With -A (allow all), as Fresh's own tasks use, the token is readable. For code you don't trust, list the hosts and variables it needs and leave out the rest.

5. Serve the built site on a private URL#

deno task build-www built the Fresh website with Vite in about 10 seconds. Fresh serves the result with deno serve. --parallel starts one worker per CPU. Bind it to 127.0.0.1 so it stays off the sandbox's public IPv6 address even if you open the firewall later, then host the port with --localhost:

sbx exec sb_sqzi8b8j3p --cwd fresh/www --detach "deno serve -A --parallel --host 127.0.0.1 --port 8000 _fresh/server.js > /home/user/serve.log 2>&1"
sbx exec sb_sqzi8b8j3p "cat serve.log"
sbx host sb_sqzi8b8j3p 8000 --localhost --title "Fresh www"
deno serve: Listening on http://127.0.0.1:8000/ with 2 threads
{"ok":true,"type":"port.hosted","sandboxId":"sb_sqzi8b8j3p","port":8000,"url":"https://jovial-mighty-ember-8000.box.sandboxer.com?_token=<token>","access":"private","isProtected":true,"localhost":true}

Without the token the URL answered 401. The token link answered 302 and set a cookie. With the cookie, /docs/introduction answered 200 with the 71.5 KB page titled "Introduction | Fresh docs". Five requests from our test machine took 0.25 to 0.40 seconds each; the same page took 0.06 seconds from inside the sandbox. Sharing and public access are in Give a sandbox port an HTTPS URL.

Fresh's dev server, deno task www, runs Vite. We didn't run it here. Vite only answers hostnames it knows; the server.allowedHosts fix for hosted URLs is in the Node starter.

6. Compile a binary for another OS#

deno compile bundles a script and the Deno runtime into one executable. The permission flags you pass are baked in:

for t in x86_64-unknown-linux-gnu aarch64-apple-darwin x86_64-pc-windows-msvc; do
  deno compile -q --allow-net=jsr.io --allow-env=HOME --target $t -o dist/fetch-$t fetch.ts
done
file dist/*
./dist/fetch-x86_64-unknown-linux-gnu
./dist/fetch-x86_64-unknown-linux-gnu https://example.com
dist/fetch-aarch64-apple-darwin:       Mach-O 64-bit arm64 executable, …
dist/fetch-x86_64-pc-windows-msvc.exe: PE32+ executable (console) x86-64, for MS Windows, 9 sections
dist/fetch-x86_64-unknown-linux-gnu:   ELF 64-bit LSB pie executable, x86-64, …
200 https://jsr.io/@std/http/meta.json
HOME is /home/user
error: Uncaught (in promise) NotCapable: Requires net access to "example.com:443", specify the required permissions during compilation using `deno compile --allow-net`

The Linux binary is 105 MB, macOS 68 MB and Windows 80 MB. The first compile for each target took 1.2 to 1.7 seconds; for macOS and Windows, Deno downloaded that target's runtime into ~/.cache/deno/dl (93 MB for both). A repeat Linux compile took 0.45 seconds. Copy a binary out with sbx scp, as in the Go starter. We checked the file types, not a run on macOS or Windows.

7. Save it as a named snapshot#

Stop background servers first; a snapshot keeps files, not processes. Then run each command you want warm, and save:

sbx exec sb_07hfqlmhrn --timeout 120 bash -lc "cd fresh && deno task check:types && deno test -A --parallel packages/fresh/src"
sbx snapshot sb_07hfqlmhrn deno-cache
sbx new --name deno-2 --type small --from deno-cache

The save took 2.1 seconds and the new sandbox was ready in 3.2. It holds Deno 2.9.8, the clone with vendor/, node_modules/ and the built site, ~/.cache/deno and the Astral Chrome. In the new sandbox:

== install, as saved
0.334 s
== check:types, as saved (1)
6.089 s
== check:types, as saved (2)
5.807 s
== unit tests, as saved
ok | 316 passed (14 steps) | 0 failed | 4 ignored (10s)
11.996 s
== build-www
10.697 s

Compare a new sandbox with no snapshot: 1.9 seconds to install Deno, 3.1 to clone, 3.0 to 5.3 for deno install and about 15 for the type check. To name the snapshot after a hash of deno.lock and rebuild it when the lockfile changes, follow Cache dependencies in a named snapshot.

FAQ#

Is Deno pre-installed in a Sandboxer sandbox?#

No, not on 2026-10-27. The official script installs it into ~/.deno in about 2 seconds. Pass a version, such as sh -s -- -y v2.9.8, to pin it.

Where does Deno keep its cache in a sandbox?#

DENO_DIR is /home/user/.cache/deno. It holds remote modules, npm packages and the type-check cache. It is on the sandbox disk, so it survives sbx stop and is saved in a named snapshot or a fork.

Why is deno check still slow after I restored my snapshot?#

The type-check cache only covers the module graphs you checked before saving. deno test and deno check check different graphs. Run each command you will use, then save.

Do Deno permissions replace the sandbox?#

No. Deno permissions limit one process. The sandbox is a separate VM that keeps the code off your machine. Use both for untrusted code; see best ways to run untrusted code safely.

Can deno compile build a macOS or Windows binary in a sandbox?#

Yes. Pass --target, for example aarch64-apple-darwin or x86_64-pc-windows-msvc. Deno downloads that target's runtime on first use. We checked the output file types, not a run on those systems.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide