DaytonaDocs
Working with Sandboxes

Working with Files

Upload, download, and manage files inside a sandbox.

Every sandbox exposes a filesystem API through sandbox.fs, so you can move code and data in and out and manage files without shelling in. Uploads and downloads work on raw bytes, which makes them easy to wire to local files, in-memory content, or network streams. All paths are paths inside the sandbox.

File operations at a glance

OperationPythonTypeScript
Upload bytes to a pathupload_file(content, remote_path)uploadFile(buffer, remotePath)
Download a file's bytesdownload_file(remote_path)downloadFile(remotePath)
List a directorylist_files(path)listFiles(path)
File metadataget_file_details(path)getFileDetails(path)
Create a foldercreate_folder(path, mode)createFolder(path, mode)
Deletedelete_file(path)deleteFile(path)
Move / renamemove_files(source, destination)moveFiles(source, destination)
Grep file contentsfind_files(path, pattern)findFiles(path, pattern)
Find files by namesearch_files(path, pattern)searchFiles(path, pattern)
Replace across filesreplace_in_files(files, pattern, new_value)replaceInFiles(files, pattern, newValue)
Permissions / ownershipset_file_permissions(path, mode, owner, group)setFilePermissions(path, { mode, owner, group })

Uploads and downloads accept a timeout parameter (default 30 minutes) for large transfers.

A typical workflow: upload, run, download

The most common shape is a three-step loop — push inputs in, run something, pull results out:

Python
# 1. Upload a script and its input.
sandbox.fs.create_folder("/workspace/job", "755")
with open("process.py", "rb") as f:
    sandbox.fs.upload_file(f.read(), "/workspace/job/process.py")
sandbox.fs.upload_file(b'{"n": 42}', "/workspace/job/input.json")
 
# 2. Run it.
result = sandbox.process.exec("python process.py", cwd="/workspace/job")
assert result.exit_code == 0, result.result
 
# 3. Download the output.
output = sandbox.fs.download_file("/workspace/job/output.json")
with open("output.json", "wb") as f:
    f.write(output)
TypeScript
import { readFile, writeFile } from 'node:fs/promises'
 
// 1. Upload a script and its input.
await sandbox.fs.createFolder('/workspace/job', '755')
await sandbox.fs.uploadFile(await readFile('process.py'), '/workspace/job/process.py')
await sandbox.fs.uploadFile(Buffer.from('{"n": 42}'), '/workspace/job/input.json')
 
// 2. Run it.
const result = await sandbox.process.executeCommand('python process.py', '/workspace/job')
if (result.exitCode !== 0) throw new Error(result.result)
 
// 3. Download the output.
const output = await sandbox.fs.downloadFile('/workspace/job/output.json')
await writeFile('output.json', output)

Inspecting and searching

list_files returns directory entries with name, size, and permission metadata; get_file_details returns the same for a single path. For finding things, there are two complementary calls: find_files greps inside files under a path and returns matches with file, line, and content, while search_files matches file names against a pattern.

Python
# Where is "TODO" mentioned?
matches = sandbox.fs.find_files("/workspace", "TODO")
for m in matches:
    print(f'{m["file"]}:{m["line"]}: {m["content"]}')
 
# Which files are tests?
found = sandbox.fs.search_files("/workspace", "test_*.py")
print(found["files"])
TypeScript
const matches = await sandbox.fs.findFiles('/workspace', 'TODO')
for (const m of matches) console.log(`${m.file}:${m.line}: ${m.content}`)
 
const found = await sandbox.fs.searchFiles('/workspace', 'test_*.py')
console.log(found.files)

Bulk edits and permissions

replace_in_files applies a search-and-replace across a list of files in one call and reports per-file success — handy for config rewrites before a run. set_file_permissions covers the chmod/chown cases:

Python
sandbox.fs.replace_in_files(
    ["/workspace/config.yaml", "/workspace/.env"],
    "localhost", "db.internal",
)
sandbox.fs.set_file_permissions("/workspace/run.sh", mode="755")
TypeScript
await sandbox.fs.replaceInFiles(
  ['/workspace/config.yaml', '/workspace/.env'],
  'localhost', 'db.internal',
)
await sandbox.fs.setFilePermissions('/workspace/run.sh', { mode: '755' })

Large or shared data

Per-sandbox upload is the right tool for code and small inputs. For anything large, reused across sandboxes, or shared between them, prefer platform storage instead of re-uploading:

  • Volumes — persistent directory trees that attach to sandboxes and survive them; ideal for datasets, caches, and build artifacts.
  • Object stores — mount an S3-compatible bucket directly inside the sandbox.

See also

On this page