# How Do I Run Deno in a Cloud Sandbox?

> 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.

Source: https://sandboxer.com/guides/run-deno-in-a-cloud-sandbox. Updated 2026-10-27.

**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](https://github.com/denoland/fresh/tree/86d6cdeb331a719cf8b1c85bf5e43c8ffa889b3b), 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](/guides/whats-preinstalled-in-a-sandbox)). `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](https://docs.deno.com/runtime/getting_started/installation/):

```bash
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"
```

```text
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

```bash
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`](https://docs.deno.com/runtime/reference/cli/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`](https://docs.deno.com/runtime/reference/cli/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:

```bash
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
```

```text
== 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:

```bash
sbx exec sb_sqzi8b8j3p --detach "bash -l b2.sh > b2.log 2>&1"
sbx exec sb_sqzi8b8j3p "tail -3 test1.log"
```

```text
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](https://jsr.io/@astral/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](https://docs.deno.com/runtime/fundamentals/security/)). That is useful when an agent runs code it wrote. This script fetches a URL and reads `HOME`:

```typescript
// 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"));
```

```bash
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
```

```text
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](/guides/environment-variables-inside-a-sandbox)). A script that reads `HOME` and `SANDBOXER_TOKEN`, run two ways:

```text
--- 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`](https://docs.deno.com/runtime/reference/cli/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`:

```bash
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"
```

```text
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](/guides/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](/guides/node-dev-environment-in-a-cloud-sandbox).

## 6. Compile a binary for another OS

[`deno compile`](https://docs.deno.com/runtime/reference/cli/compile/) bundles a script and the Deno runtime into one executable. The permission flags you pass are baked in:

```bash
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
```

```text
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](/guides/go-dev-environment-in-a-cloud-sandbox). 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:

```bash
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:

```text
== 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](/guides/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](/guides/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.

## Related

- [Set up a Node.js dev environment in a cloud sandbox](/guides/node-dev-environment-in-a-cloud-sandbox)
- [Cache dependencies in a named snapshot](/guides/cache-dependencies-in-a-named-snapshot)
- [What's pre-installed in a sandbox](/guides/whats-preinstalled-in-a-sandbox)
- [Hosting docs](/docs/hosting)
