Skip to content
sandbox-workers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Manage files

Read, write, and organize files under /workspace with the typed client and from guest code.

Every sandbox owns a writable /workspace directory, reachable both from guest code and from the caller through a files API. /workspace is shared by every code context in the sandbox regardless of binding, so files written from a Python context are visible from a JavaScript one. This guide shows you how to work with those files from your Worker and from the code you execute. Your own Worker can turn the whole File API off with SANDBOX_FILE_API=disabled (see Environment variables) — everything below assumes it’s enabled, which it is by default.

Use the client’s file methods

import { getSandbox } from "@sandbox-workers/core";

export { Sandbox } from "@sandbox-workers/core";

const sandbox = getSandbox(env.Sandbox, "user-42");

Write a file

await sandbox.writeFile("/workspace/app.py", "print('hi')");
// content is a string, Uint8Array, or ReadableStream<Uint8Array>; pass { encoding: "base64" } for base64 strings

Read a file

const file = await sandbox.readFile("/workspace/app.py");
console.log(file.content);

const stream = await sandbox.readFile("/workspace/image.png", { encoding: "none" });
// stream.content is a ReadableStream<Uint8Array>

List files

const { files } = await sandbox.listFiles("/workspace", { recursive: true });

Create a directory

await sandbox.mkdir("/workspace/project/src", { recursive: true });

Delete a file

await sandbox.deleteFile("/workspace/old.txt", { force: true });
// a directory needs recursive: true; force: true ignores a missing path

Rename or move a file

await sandbox.renameFile("/workspace/draft.md", "/workspace/final.md");
await sandbox.moveFile("/workspace/report.csv", "/workspace/archive/report.csv");
// move additionally requires the destination's parent directory to exist

Check whether a file exists

await sandbox.exists("/workspace/config.json");

See the files API reference for each method’s full signature and return type.

Access files from guest code

JavaScript

fs is a host-backed synchronous subset of Node’s fs:

fs.readFileSync(path, "utf8"); // string; without an encoding, a Uint8Array
fs.writeFileSync(path, data); // string or Uint8Array
fs.readdirSync(path, { withFileTypes });
fs.mkdirSync(path, { recursive });
fs.rmSync(path, { recursive, force });
fs.renameSync(from, to);
fs.existsSync(path);
fs.statSync(path); // { size, mtimeMs, isFile(), isDirectory() }

Errors carry the same Node-style code values as the client’s file methods. import() (and static import inside a module loaded through it) is served from /workspace: ./ and ../ specifiers resolve against the importing module, and only .js/.mjs and .json (with {type: "json"}) files are served — anything outside /workspace fails to resolve.

Python

sys.path includes /workspace, so modules written there can be imported. os.chdir(cwd) changes the working directory used by relative paths; in a code context, the final os.getcwd() is persisted across executions when it is under /workspace.

Perl

chdir($cwd) changes the working directory. In a code context, Cwd::getcwd() is persisted across executions.

Limits

  • 1 MiB per file
  • 16 MiB per workspace
  • 4096 entries

Handle errors

A file operation failure throws the matching SandboxError subclass — FileNotFoundError, FileExistsError, FileTooLargeError, PermissionDeniedError, or FileSystemError — with the path and operation on error.context, and, for filesystem failures, the Node-style errno in error.context.errno.

import { FileNotFoundError } from "@sandbox-workers/core";

try {
  await sandbox.readFile("/workspace/missing.txt");
} catch (error) {
  if (error instanceof FileNotFoundError) {
    // error.code === "FILE_NOT_FOUND", error.httpStatus === 404
  }
}

See errors for the full SandboxError hierarchy and error code table.