Vercel Logo

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:

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']);
  console.log(`Clone exit code: ${clone.exitCode}`);
 
  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${await 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 the exit code immediately; output is available through async methods such as await clone.stderr().

The URL is a separate argument instead of part of a shell string. That prevents repository input from being interpreted as shell syntax, even if another caller bypasses the CLI's URL validation later.

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.

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.

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

pnpm tsx src/sandbox-lifecycle.ts

Expected output (success case):

Sandbox created: repo-review-...
Clone exit code: 0
Cloned https://github.com/vercel/examples into repo

And the failure case (bad URL):

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

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

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']);
  console.log(`Clone exit code: ${clone.exitCode}`);
 
  if (clone.exitCode !== 0) {
    console.error(`Clone failed: ${await clone.stderr()}`);
  } else {
    console.log(`Cloned ${REPO_URL} into repo`);
  }
 
  await sandbox.stop();
}
 
main();

Was this helpful?

supported.