---
title: "Read Files"
description: "We've cloned the repo, but we haven't looked inside. In this lesson, we list the cloned directory with `ls`, read the README out of the Sandbox, and handle the case where the file isn't there."
canonical_url: "https://vercel.com/academy/vercel-sandbox/read-files"
md_url: "https://vercel.com/academy/vercel-sandbox/read-files.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-08-21T16:55:06.960Z"
content_type: "lesson"
course: "vercel-sandbox"
course_title: "Vercel Sandbox"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Read Files

# Read Files from the Sandbox

We cloned a repo. Now we should probably look at what we got.

There are two ways to inspect a cloned project from outside the Sandbox: run a shell command and parse the output, or read files directly with the SDK. We're going to do both, because both come in handy.

## Outcome

List the cloned repo's contents with `ls`, read a file with `sandbox.readFileToBuffer`, and handle the case where the file you wanted doesn't exist.

## Fast Track

1. Run `ls -la repo` and log the output.
2. Read `repo/README.md` with `sandbox.readFileToBuffer`.
3. Add a fallback so a missing file doesn't crash the script.

## Hands-on exercise

Extend `src/sandbox-lifecycle.ts` after the clone step:

```ts
import { Sandbox } from '@vercel/sandbox';

const REPO_URL = 'https://github.com/vercel/examples';

async function main() {
  const sandbox = await Sandbox.create({ persistent: false, timeout: 10 * 60 * 1000 });
  console.log(`Sandbox created: ${sandbox.name}`);

  const clone = await sandbox.runCommand('git', ['clone', '--depth', '1', REPO_URL, 'repo']);
  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${await clone.stderr()}`);
    await sandbox.stop();
    return;
  }

  const ls = await sandbox.runCommand('ls', ['-la', 'repo']);
  console.log('--- repo contents ---');
  console.log(await ls.stdout());

  let readmePreview = '(no README found)';
  const readme = await sandbox.readFileToBuffer({ path: 'repo/README.md' });
  if (readme) {
    readmePreview = readme.toString('utf8').slice(0, 300);
  }

  console.log('--- README preview ---');
  console.log(readmePreview);

  await sandbox.stop();
}

main();
```

Two things to notice. First, `readFileToBuffer` accepts a `{ path }` object and resolves to `null` when the file is missing. Some repos use lowercase `readme.md`, some put docs in a `docs/` folder, and some don't have one at all. A null check keeps the script moving.

Second, we bailed early on a failed clone. Continuing past a failed clone means everything after it fails for confusing reasons. Fail fast, fail loud.

\*\*Warning: Troubleshooting: readFileToBuffer returns null\*\*

`null` means the path was not found. An empty Buffer means the file exists but is empty. Check the exact filename in the `ls` output.

\*\*Note: Troubleshooting: path mismatch\*\*

`readFileToBuffer({ path: 'repo/README.md' })` is case-sensitive on the Sandbox filesystem. If `ls` shows `Readme.md` or `readme.md`, match the case exactly.

## Try It

```bash
pnpm tsx src/sandbox-lifecycle.ts
```

Expected output:

```txt
Sandbox created: sbx_7N2k4A...
--- repo contents ---
total 32
drwxr-xr-x  ... .git
-rw-r--r--  ... README.md
-rw-r--r--  ... package.json
drwxr-xr-x  ... examples
--- README preview ---
# Vercel Examples

This repository contains a set of example projects...
```

If `README.md` doesn't exist in the repo you're testing, you'll see `(no README found)` instead of crashing. That's the point.

## Commit

```bash
git add src/sandbox-lifecycle.ts
git commit -m "feat(sandbox): list directory and read files from sandbox"
```

## Done-When

- [ ] `ls -la repo` returns the cloned directory listing
- [ ] `sandbox.readFileToBuffer` returns the README contents on a real repo
- [ ] Missing README logs a warning instead of crashing
- [ ] The script still stops the Sandbox at the end

## Solution

```ts title="src/sandbox-lifecycle.ts"
import { Sandbox } from '@vercel/sandbox';

const REPO_URL = 'https://github.com/vercel/examples';

async function main() {
  const sandbox = await Sandbox.create({ persistent: false, timeout: 10 * 60 * 1000 });
  console.log(`Sandbox created: ${sandbox.name}`);

  const clone = await sandbox.runCommand('git', ['clone', '--depth', '1', REPO_URL, 'repo']);
  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${await clone.stderr()}`);
    await sandbox.stop();
    return;
  }

  const ls = await sandbox.runCommand('ls', ['-la', 'repo']);
  console.log('--- repo contents ---');
  console.log(await ls.stdout());

  let readmePreview = '(no README found)';
  const readme = await sandbox.readFileToBuffer({ path: 'repo/README.md' });
  if (readme) {
    readmePreview = readme.toString('utf8').slice(0, 300);
  }

  console.log('--- README preview ---');
  console.log(readmePreview);

  await sandbox.stop();
}

main();
```


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
