runtime or named outright with image. Five runtimes come built in.
node and python are the stock Docker Hub images. node-python, media and browser are built from images/ in the
nativesandbox repository for linux/amd64 and linux/arm64, and tagged with the package version, so
nativesandbox@0.4.0 uses nativesandbox-node-python:0.4.0. Sizes are uncompressed, on disk.
node-python
Node and Python in one image. node has no Python and python has no npm, so a job that edits with a Python
script and builds with npm needs two sandboxes on the stock images — and since the image is part of a sandbox’s
identity, switching between them replaces the sandbox and loses whatever it had installed. node-python keeps
it to one.
- Node 22 and npm, Python 3 (Alpine’s, 3.14 at the time of writing) with pip, git and curl.
pythonis linked topython3.PIP_BREAK_SYSTEM_PACKAGES=1: a sandbox is disposable, sopip installgoes into the system Python rather than being refused.
media
Everything in node-python, plus ffmpeg and libvips, for video and images.
browser
Everything in node-python, plus headless Chromium driven by Playwright, and axe for accessibility. Only the
headless build is installed — the one chromium.launch() uses; full Chromium is for headed runs, which a sandbox
has no use for.
The packages are installed globally, so a script can import or require them without an npm install —
which would otherwise download a browser on every run. require() finds them through NODE_PATH; ESM import
ignores NODE_PATH, so a small resolve hook, loaded through NODE_OPTIONS, retries a bare import from the global
directory once normal resolution has failed. A project’s own node_modules always wins, and npm install behaves
exactly as anywhere else.
/dev/shm. Chromium needs about a gigabyte; give the sandbox MiB(1024) or more. It also keeps
renderer state in /dev/shm, and an engine’s default 64 MB crashes it on an ordinary page, so the browser
runtime gets 512 MiB by default — see RUNTIME_DEFAULTS and the shmSize option in
Resource limits.
No capabilities. Under the default hardening every capability is dropped, so Chromium’s
own sandbox cannot start. Playwright already launches Chromium without it (chromiumSandbox: false); a tool
that launches CHROME_PATH itself must pass --no-sandbox. The container is the sandbox.
Pulling
An image is pulled the first time a runtime is asked for. That is fine for the Alpine images and wrong forbrowser: a first command that waits for several hundred megabytes blows any reasonable timeout. Pull ahead, at
deploy or at boot:
Versions
The built images follow the package version. A sandbox’s image is part of its identity —create() never reuses
a sandbox across images — so upgrading nativesandbox hands out fresh sandboxes on the new images rather than
mixing versions.
Bring your own image
Name an image for one sandbox, or change the mapping for every one:sh, which runs the self-stop watchdog and every command,
and a writable /workspace, where the workspace is mounted. Anything else is up to you.