Skip to content
sandbox-workers
Esc
navigateopen⌘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.

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.