---
title: "Clone a Repo"
description: "Echoing strings is fine, but the whole point is to inspect real code. In this lesson, we run `git clone` inside the Sandbox, verify the exit code, and confirm the repo actually landed where we expected it."
canonical_url: "https://vercel.com/academy/vercel-sandbox/clone-a-repo"
md_url: "https://vercel.com/academy/vercel-sandbox/clone-a-repo.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-05-17T05:31:25.301Z"
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>

# Clone a Repo

# Clone a Repo into the Sandbox

Echoing strings is cute, but nobody hires you to print "hello." We want to look at real code, in isolation, without trusting it. Step one is getting that code into the Sandbox.

Git is already available inside the Sandbox base image. Cloning is just another `runCommand`. The interesting part isn't the clone itself, it's verifying that the clone actually worked.

## Outcome

Run `git clone` inside the Sandbox against a real GitHub URL, capture the exit code, and confirm the repo landed in the expected directory.

## Fast Track

1. Pick a public repo URL (we'll use `https://github.com/vercel/examples`).
2. Run `git clone <url> repo` inside the Sandbox.
3. Check the exit code and log a confirmation.

## Hands-on exercise

Open `src/sandbox-lifecycle.ts` and replace the echo with a clone:

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

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

async function main() {
  const sandbox = await Sandbox.create();
  console.log(`Sandbox created: ${sandbox.sandboxId}`);

  const clone = await sandbox.runCommand(`git clone ${REPO_URL} repo`);
  console.log(`Clone exit code: ${clone.exitCode}`);

  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${clone.stderr}`);
  } else {
    console.log(`Cloned ${REPO_URL} into /repo`);
  }

  await sandbox.stop();
}

main();
```

Notice we're checking `exitCode` instead of assuming success. `runCommand` doesn't throw when the underlying command fails. It returns `exitCode`, `stdout`, and `stderr`, and it's our job to do something with that.

Try breaking it on purpose. Change the URL to `https://github.com/this-does-not-exist/nope` and run it again. You'll see a non-zero exit code and a "Repository not found" message in `stderr`. That's the shape of failure we'll keep checking for.

\*\*Warning: Troubleshooting: clone hangs\*\*

If the clone hangs for more than \~60s, the Sandbox image may be missing `git` or the URL is unreachable from inside the microVM. Run `which git` as a quick `runCommand` to confirm git is present.

\*\*Note: Troubleshooting: cloning private repos\*\*

Public repos clone fine over HTTPS with no credentials. Private repos need an auth token, which we won't cover in this course. Stick to public URLs.

## Try It

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

Expected output (success case):

```txt
Sandbox created: sbx_7N2k4A...
Clone exit code: 0
Cloned https://github.com/vercel/examples into /repo
```

And the failure case (bad URL):

```txt
Sandbox created: sbx_7N2k4A...
Clone exit code: 128
Clone failed: fatal: repository 'https://github.com/this-does-not-exist/nope/' not found
```

Both are good. The first proves the happy path works; the second proves we notice when it doesn't.

## Commit

```bash
git add src/sandbox-lifecycle.ts
git commit -m "feat(sandbox): clone a repo and check the exit code"
```

## Done-When

- [ ] `git clone` runs inside the Sandbox
- [ ] Exit code is captured and printed
- [ ] Success case logs a confirmation
- [ ] Failure case logs `stderr` instead of silently passing

## 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();
  console.log(`Sandbox created: ${sandbox.sandboxId}`);

  const clone = await sandbox.runCommand(`git clone ${REPO_URL} repo`);
  console.log(`Clone exit code: ${clone.exitCode}`);

  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${clone.stderr}`);
  } else {
    console.log(`Cloned ${REPO_URL} into /repo`);
  }

  await sandbox.stop();
}

main();
```


---

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