> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blaxel.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# File system

> Read, write, list, and delete files inside a Blaxel sandbox using a simple file system interface from the SDK, MCP server, or REST API.

Manage files and directories within sandboxes through the `fs` module of Blaxel SDK. This module provides essential operations for creating, reading, writing, copying, and deleting files and directories.

<Tip>Complete code examples demonstrating all operations are available on Blaxel's GitHub: [in TypeScript](https://github.com/blaxel-ai/sdk-typescript/tree/main/tests/sandbox), [in Python](https://github.com/blaxel-ai/sdk-python/tree/main/tests/integration/sandbox), and [in Go](https://github.com/blaxel-ai/sdk-go/tree/main/integration_tests).</Tip>

## Basic file system operations

<Accordion title="Learn more about authentication on Blaxel">
  The Blaxel SDK requires two environment variables to authenticate:

  | Variable       | Description                |
  | -------------- | -------------------------- |
  | `BL_WORKSPACE` | Your Blaxel workspace name |
  | `BL_API_KEY`   | Your Blaxel API key        |

  You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`).

  Set them as environment variables or add them to a `.env` file at the root of your project:

  ```bash theme={null}
  export BL_WORKSPACE=my-workspace
  export BL_API_KEY=my-api-key
  ```

  The Blaxel SDK does not accept credentials as constructor arguments. Credentials must come from environment variables, a `.env` file, or a local CLI login session (see below).

  When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed.
</Accordion>

### Create directory

Create a new directory at a specific path in the sandbox:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SandboxInstance } from "@blaxel/core";

  const sandbox = await SandboxInstance.get("my-sandbox");

  await sandbox.fs.mkdir("/blaxel/app/uploads");
  ```

  ```python Python theme={null}
  from blaxel.core import SandboxInstance

  sandbox = await SandboxInstance.get("my-sandbox")
  await sandbox.fs.mkdir("/blaxel/app/uploads")
  ```
</CodeGroup>

### List files

List files in a specific path:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { subdirectories, files } = await sandbox.fs.ls("/blaxel/app");
  ```

  ```python Python theme={null}
  result = await sandbox.fs.ls("/blaxel/app")
  directories = result.subdirectories
  files = result.files
  ```
</CodeGroup>

### Find files and directories

<Note>
  Blaxel's Sandbox API uses an optimized `find()` method, which is faster than using the native `find` tool.
</Note>

Find files and directories matching specified patterns:

<CodeGroup>
  ```typescript TypeScript theme={null}
  let result = await sandbox.fs.find(
    "/app",
    {
      type: "file",
      patterns: ["*.md", "*.html"],
      maxResults: 1000,
    }
  );

  if (result.matches && result.matches.length > 0) {
    for (const file of result.matches) {
      console.log(`Found file: ${file.path}`);
    }
  } else {
    console.log("No files found.");
  }
  ```

  ```python Python theme={null}
  result = await sandbox.fs.find(
      path="/app",
      type="file",
      patterns=["*.md", "*.html"],
      max_results=1000,
  )
  if result.matches:
      for file in result.matches:
          logger.info(f"Found file: {file.path}")
  else:
      logger.info("No files found.")
  ```
</CodeGroup>

### Search for text content within files

<Note>
  Blaxel's Sandbox API uses an optimized `grep()` method, which is faster than using the native `grep` tool.
</Note>

Find files containing specified text content:

<CodeGroup>
  ```typescript TypeScript theme={null}
  let result = await sandbox.fs.grep(
    "agentic",
    "/app",
    {
      caseSensitive: true,
      contextLines: 2,
      maxResults: 5,
      filePattern: "*.mdx",
      excludeDirs: ["images", "node_modules"],
    }
  );

  if (result.matches && result.matches.length > 0) {
    for (const match of result.matches) {
      console.log(`${match.path}:${match.line} -> ${match.text}`);
    }
  } else {
    console.log("No matches found.");
  }
  ```

  ```python Python theme={null}
  result = await sandbox.fs.grep(
      query="agentic",
      path="/app",
      case_sensitive=True,
      context_lines=2,
      max_results=5,
      file_pattern="*.mdx",
      exclude_dirs=["images", "node_modules"],
  )
  if result.matches:
      for match in result.matches:
          logger.info(
              f"{match.path}:{match.line} -> {match.text}"
          )
  else:
      logger.info("No matches found.")
  ```
</CodeGroup>

### Read file

Read a file from a specific filepath:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const content = await sandbox.fs.read("/blaxel/app/config.json");
  ```

  ```python Python theme={null}
  content = await sandbox.fs.read("/blaxel/app/config.json")
  ```
</CodeGroup>

### Write file

Create a file in a specific path:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await sandbox.fs.write("/blaxel/app/config.json", "{}");
  ```

  ```python Python theme={null}
  await sandbox.fs.write("/blaxel/app/config.json", "{}")
  ```
</CodeGroup>

See down below for how to upload/write a binary, or multiple files at once.

### Write multiple files

You can write multiple files or directories simultaneously. The second path parameter in `writeTree` specifies the base directory for writing the file tree, eliminating the need to repeat the full path for each file.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const files = [
    { path: "src/app.js", content: "console.log('Hello');" },
    { path: "src/utils.js", content: "export const helper = () => {};" },
    { path: "package.json", content: '{"name": "my-app"}' },
    { path: "docs/README.md", content: "# My App" }
  ];
  await sandbox.fs.writeTree(files, "/blaxel/app");
  ```

  ```python Python theme={null}
  files = [
      {"path": "src/app.py", "content": "print('Hello')"},
      {"path": "src/utils.py", "content": "def helper(): pass"},
      {"path": "requirements.txt", "content": "flask==2.0.1"},
      {"path": "docs/README.md", "content": "# My App"}
  ]
  await sandbox.fs.write_tree(files, "/blaxel/app")
  ```
</CodeGroup>

### Read binary file

Read a binary file from the sandbox filesystem:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const binaryData = await sandbox.fs.readBinary("/tmp/image.webp");
  ```

  ```python Python theme={null}
  binary_data = await sandbox.fs.read_binary("/tmp/image.webp")
  ```
</CodeGroup>

The binary content is returned as a Web API *Blob* object.

### Write binary file

Write binary content to a file in the sandbox filesystem:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const binaryData = fs.readFileSync("./image.webp");
  await sandbox.fs.writeBinary("/blaxel/app/assets/image.webp", binaryData);
  ```

  ```python Python theme={null}
  with open("image.webp", "rb") as f:
      binary_data = f.read()
      await sandbox.fs.write_binary("/blaxel/app/assets/image.webp", binary_data)
  ```
</CodeGroup>

The binary content to write can be provided as:

* *Buffer*: Node.js Buffer object
* *Blob*: Web API Blob object
* *File*: Web API File object
* *Uint8Array*: Typed array containing binary data

### Download file to host

Download a file from the sandbox filesystem to the host:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await sandbox.fs.download("/tmp/foo.bin", "foo2.bin");
  ```

  ```python Python theme={null}
  await sandbox.fs.download("/tmp/foo.bin", "foo2.bin")
  ```
</CodeGroup>

### Copy file

Copy a file from a path to another path:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await sandbox.fs.cp("/blaxel/app/config.json", "/blaxel/app/config.backup.json");
  ```

  ```python Python theme={null}
  await sandbox.fs.cp("/blaxel/app/config.json", "/blaxel/app/config.backup.json")
  ```
</CodeGroup>

### Delete file or directory

Delete a file or directory by specifying its path:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await sandbox.fs.rm(`/blaxel/app/config.json`);
  ```

  ```python Python theme={null}
  await sandbox.fs.rm(f"/blaxel/app/config.json")
  ```
</CodeGroup>

## Watch filesystem for events

The `watch` function monitors all file system changes **in the specified directory.** You can also watch subdirectories by passing a `/my/directory/**` pattern.

By default (when *withContent: false*), the events will only include metadata about the changes, not the actual file contents. Here's what you'll get in the callback events:

1. For ALL operations (CREATE, WRITE, DELETE, etc.), you'll receive:
   1. op: The operation type (e.g., "CREATE", "WRITE", "DELETE")
   2. path: The directory path where the change occurred
   3. name: The name of the file/directory that changed
2. You will NOT receive:
   1. The actual content of the files
   2. File contents for CREATE or WRITE operations

<CodeGroup>
  ```typescript TypeScript theme={null}
  // You can specify if you want the content of the files or not
  const handle = sandbox.fs.watch("/", (fileEvent) => {
    console.log(fileEvent.op, fileEvent.path, fileEvent.content)
  }, {
    withContent: true
  });

  // Do file operations

  // At the end, close the watch handle
  handle.close();
  ```

  ```python Python theme={null}
  def watch_callback(file_event):
    print(file_event.op, file_event.path, file_event.content)

  # You can specify if you want the content of the files or not
  handle = sandbox.fs.watch("/", watch_callback, { "with_content": True })

  # Do file operations

  # At the end, close the watch handle
  handle["close"]()
  ```
</CodeGroup>

### Watch sub-directories

Watch all sub-directories recursively with `/**`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const handle = sandbox.fs.watch("/folder/**", (fileEvent) => {
    console.log(fileEvent.op, fileEvent.path)
  });

  ```

  ```python Python theme={null}
  def watch_callback(file_event):
    print(file_event.op, file_event.path)

  # You can specify if you want the content of the files or not
  handle = sandbox.fs.watch("/folder/**", watch_callback)
  ```
</CodeGroup>

### Ignore files or directories

You can ignore changes in certain files or directories by providing an array of filepaths to ignore:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const handle = sandbox.fs.watch("/", (fileEvent) => {
    console.log(fileEvent.op, fileEvent.path)
  }, {
    ignore: ["/folder", "/folder_two/test2.txt"]
  });
  ```

  ```python Python theme={null}
  def watch_callback(file_event):
    print(file_event.op, file_event.path)

  # You can specify if you want the content of the files or not
  handle = sandbox.fs.watch("/", watch_callback, {
    "ignore": ["/folder", "/folder_two/test2.txt"]
  })
  ```
</CodeGroup>

Specify `withContent: true` so the events include the actual file contents.
