# Migrate from GitHub Codespaces to Sandboxer

> Turn your devcontainer.json postCreateCommand into a setup script, create the sandbox with sbx new --setup-file, and save the result as a named snapshot. Replace gh codespace ssh with sbx ssh-config and Remote-SSH, and forwarded ports with hosted HTTPS ports. Agents can then run past Codespaces' 12-hour limit.

Source: https://sandboxer.com/migrate/github-codespaces. Updated 2026-10-27.

**Short answer:** Turn your devcontainer.json postCreateCommand into a setup script, create the sandbox with sbx new --setup-file, and save the result as a named snapshot. Replace gh codespace ssh with sbx ssh-config and Remote-SSH, and forwarded ports with hosted HTTPS ports. Agents can then run past Codespaces' 12-hour limit.

This page is for teams that use Codespaces to run coding agents unattended. Two Codespaces limits get in the way. A codespace stops after an idle timeout, 30 minutes by default and at most 240 minutes. It also has a maximum lifetime of 12 hours, whatever the idle setting ([GitHub docs](https://docs.github.com/en/codespaces/setting-your-user-preferences/setting-your-timeout-period-for-github-codespaces)). A Sandboxer sandbox is a VM whose auto-stop you set, up to 30 days or off on paid plans, and a stop keeps memory and disk.

Sandboxer doesn't read `devcontainer.json`. Its docs don't mention the file, and nothing in a sandbox acts on it. You move each part of the file by hand, which the sections below show.

## Concept map

| GitHub Codespaces | Sandboxer |
| - | - |
| Codespace: a dev container on a VM, with limited access to the host VM ([GitHub docs](https://docs.github.com/en/codespaces/overview)) | Sandbox: its own Ubuntu 24.04 VM with root through `sudo`, systemd and Docker ([Machines](/docs/machines)) |
| `devcontainer.json` `image` or `build.dockerfile` | The sandbox's Ubuntu image, plus a setup script. Or run the image yourself with Docker inside the sandbox |
| `postCreateCommand` | Setup script (`sbx new --setup-file`), watched through `setupStatus` ([Long-running tasks](/docs/long-running#setup-scripts)) |
| Dev container `features` | `apt`, `pip` or `npm` lines in the setup script |
| Prebuilt codespace state | Named snapshot, started with `--from` ([Snapshots](/docs/snapshots#named-snapshots-templates)) |
| Machine type (2 to 32 cores) | Size: `small`, `default`, `large`, `xlarge` (2 to 16 vCPU) |
| Idle timeout (stop) | Idle pause (`--idle`), a stop with memory that wakes on use ([Long-running tasks](/docs/long-running)) |
| 12-hour maximum lifetime | Auto-stop (`--ttl`), up to 30 days, or `--no-auto-stop` on paid plans |
| Forwarded port at `CODESPACENAME-PORT.app.github.dev`, private by default ([GitHub docs](https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace)) | Hosted port at `<subdomain>-PORT.box.sandboxer.com`, private by default ([Hosting](/docs/hosting)) |
| Repository the codespace is created from | `git clone` in the setup script, or repos attached to an environment ([Environments](/docs/environments)) |
| `gh` CLI | `sbx` CLI, REST API, TypeScript and Python SDKs |

## API and SDK mapping

GitHub's commands come from [Using GitHub Codespaces with GitHub CLI](https://docs.github.com/en/codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli) and our [comparison data](/compare/github-codespaces), checked 2026-10-24. Ours come from the [CLI docs](/docs/cli).

| GitHub CLI | `sbx` CLI | Sandboxer SDK (TypeScript) or REST |
| - | - | - |
| `gh codespace create -r OWNER/REPO -b BRANCH` | `sbx new --setup-file ./setup.sh` (the script clones the repo) | `POST /api/v1/sandboxes` with `setupScript` |
| `gh codespace edit -m MACHINE-TYPE` | `sbx resume <id> --type large` (grow only: shrinking isn't supported today, so create a new, smaller sandbox and copy your work) | |
| `gh codespace list` | `sbx list` | `sandboxer.list()` |
| `gh codespace ssh -c NAME` | `sbx ssh <id>`, or `ssh <id>.sbx` after `sbx ssh-config --install` | |
| `gh codespace cp [-r] SOURCE DEST` | `sbx scp [-r] SOURCE DEST` | `sandbox.files.write(path, data)` |
| `gh codespace ports forward 5000:5000 -c NAME` | `sbx forward <id> --remote 5000`, or `sbx host <id> 5000` for a URL | `sandbox.host(5000)` |
| `gh codespace stop -c NAME` | `sbx stop <id>` (keeps memory) | `sandbox.stop()` |
| `gh codespace delete -c NAME` | `sbx delete <id> --yes` | `sandbox.delete()` |
| Idle timeout setting | `sbx idle <id> 60` | |
| | `sbx exec <id> "cmd"` (no SSH needed) | `sandbox.exec("cmd")` |

## Before and after

From GitHub's docs: [Setting up a Python project for GitHub Codespaces](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/setting-up-your-python-project-for-codespaces) (step 3, comments removed):

```json
{
  "name": "Python 3",
  "image": "mcr.microsoft.com/devcontainers/python:0-3.11-bullseye",
  "features": {
    "ghcr.io/devcontainers-contrib/features/coverage-py:2": {}
  },
  "postCreateCommand": "pip3 install --user -r requirements.txt",
  "customizations": {
    "vscode": {
      "extensions": ["streetsidesoftware.code-spell-checker"]
    }
  }
}
```

From GitHub's docs: [Using GitHub Codespaces with GitHub CLI](https://docs.github.com/en/codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli):

```bash
gh codespace create -r OWNER/REPO_NAME [-b BRANCH]
gh codespace ssh -c CODESPACE-NAME
```

### After: the same setup on Sandboxer

We ran every command below on prod on 2026-10-27, with the public [pallets/flask](https://github.com/pallets/flask) repo and its tutorial app, Flaskr. The setup script does what `postCreateCommand` did, plus the clone that Codespaces does for you:

```bash
#!/bin/bash
set -e
cd ~
git clone --depth 1 https://github.com/pallets/flask
cd flask/examples/tutorial
pip3 install --user --break-system-packages -q -e . pytest
```

`--break-system-packages` is there because the sandbox's Python 3.12.3 is the system Python. Create the sandbox with the script:

```bash
sbx new --name aeo-migrate-gcs-1 --type default --ttl 3600 --setup-file ./setup.sh
```

```text
{"event":"created","id":"sb_1dnlsapog8","state":"provisioning","ttlSeconds":3600,…}
{"event":"ready","id":"sb_1dnlsapog8","state":"ready",…,"url":"https://amber-outer-hawk.box.sandboxer.com",…}
```

`sbx new` returned `ready` in 3.2 seconds (single run, 2026-10-27). The setup script runs in the background after that, so check `setupStatus` before you use the repo. It goes `pending`, `running`, then `done`, or `failed` with the reason in `setupError`:

```bash
sbx info sb_1dnlsapog8 --json
```

In our run, `setupStatus` was already `done` and `setupError` was `null` on the first check, a few seconds after `ready`. A bigger install takes longer, so poll until it leaves `running`.

Run the project's tests through the API, with no SSH session:

```bash
sbx exec sb_1dnlsapog8 --cwd flask/examples/tutorial --timeout 300 -- python3 -m pytest -q
```

```text
........................                                                 [100%]
24 passed in 0.57s
```

### SSH and VS Code Remote-SSH

`gh codespace ssh` becomes a host entry in your SSH config. Run this once:

```bash
sbx ssh-config --install
```

```text
{"ok":true,"type":"ssh.config.installed","path":"/home/you/.ssh/config","changed":true}
```

It adds a `Host *.sbx` block that tunnels through `sbx proxy` over HTTPS. Any OpenSSH tool can then reach the sandbox as `<id>.sbx`:

```bash
ssh sb_1dnlsapog8.sbx "cd flask/examples/tutorial && whoami && hostname && python3 -m pytest -q tests/test_auth.py"
```

```text
user
amber-outer-hawk
........                                                                 [100%]
8 passed in 0.39s
```

That took 2.3 seconds in our single run. In VS Code, run "Remote-SSH: Connect to Host…" and enter `sb_1dnlsapog8.sbx`. We didn't open an editor for this test. The SSH connection the editor uses is the one shown above. Sandboxer ignores `customizations.vscode.extensions`, so install extensions in the editor. See [SSH from VS Code or Cursor](/guides/ssh-into-a-cloud-sandbox-from-vs-code-or-cursor) for the full setup.

### A hosted port for the dev server

A forwarded Codespaces port becomes a hosted port. Start the dev server detached, then host its port:

```bash
sbx exec sb_1dnlsapog8 --cwd flask/examples/tutorial "python3 -m flask --app flaskr init-db"
# Initialized the database.
sbx exec sb_1dnlsapog8 --cwd flask/examples/tutorial --detach \
  "python3 -m flask --app flaskr run --host 0.0.0.0 --port 5000"
sbx host sb_1dnlsapog8 5000
```

```text
{"ok":true,"type":"port.hosted","sandboxId":"sb_1dnlsapog8","port":5000,"access":"private","isProtected":true,"url":"https://amber-outer-hawk-5000.box.sandboxer.com?_token=…"}
```

Like a Codespaces port, it's private by default. Without the token, the URL answered `401`. With the `_token` link, the Flaskr page loaded (`<title>Posts - Flaskr</title>`, HTTP 200). Add `--public` to open it to anyone. Bind the server to `0.0.0.0`, not `127.0.0.1`, or pass `--localhost` to `sbx host`.

### Save it and start from it

A named snapshot plays the part of a prebuilt environment. New sandboxes start with the repo and packages already in place:

```bash
sbx snapshot sb_1dnlsapog8 aeo-migrate-gcs-tpl
```

```text
{"ok":true,"type":"snapshot.named.info","snapshot":{…,"name":"aeo-migrate-gcs-tpl",…,"status":"ready","type":"default",…}}
```

```bash
sbx delete sb_1dnlsapog8 --yes
sbx new --name aeo-migrate-gcs-2 --type default --ttl 1800 --from aeo-migrate-gcs-tpl
sbx exec sb_w4cu93z8t8 --cwd flask/examples/tutorial -- python3 -m pytest -q
```

```text
{"event":"ready","id":"sb_w4cu93z8t8","state":"ready",…}
........................                                                 [100%]
24 passed in 0.78s
```

The new sandbox was ready in 3.2 seconds (single run), and the tests passed with no setup step. A named snapshot holds the disk, not running processes, so start the dev server again (or make it a systemd service). We then deleted the sandbox and the snapshot with `sbx delete sb_w4cu93z8t8 --yes` and `sbx snapshot rm aeo-migrate-gcs-tpl`.

## Move your data and environment

**`devcontainer.json`, field by field.**

- `postCreateCommand`: copy it into the setup script, as above. The script runs as `user` and can be up to 64 KB.
- `image` or `build`: a sandbox is an Ubuntu 24.04 VM, not your container image. Install what the image gave you in the setup script. If you need the exact image, Docker is preinstalled, so you can run it inside the sandbox.
- `features`: replace each feature with the install commands it stands for.
- `forwardPorts`: run `sbx host <id> <port>` for each port, or `host <port>` from inside the sandbox.
- `customizations`: editor settings stay in your editor. Sandboxer doesn't read them.
- `remoteUser`: you are `user`, with `sudo` for root.

**Repository and credentials.** A codespace starts with its repository checked out. On Sandboxer, clone it in the setup script, or connect GitHub on the dashboard and attach the repo to an environment with `sbx env add-repo base OWNER/REPO --branch main`. New sandboxes then clone it into `/home/user/<repo>` with a token that lets `git push` and `gh pr create` work, if the environment passes GitHub credentials ([Environments](/docs/environments)).

**Files.** Copy uncommitted work out of the codespace with `gh codespace cp`, then upload it with `sbx scp -r ./work <id>:/home/user/`. Recursive copies go as one tar stream.

**Env vars and secrets.** Codespaces secrets become environment variables and secret files: `sbx env set-var base KEY=value` and `sbx env set-file base path --from ./file`, or `-e KEY=value` on one `sbx new`.

**Keeping an agent running.** Create the sandbox with a long `--ttl`, or `--no-auto-stop` on a paid plan. Idle pause doesn't stop a sandbox while a command is running (detached ones too), an agent turn runs, someone is logged in over SSH, or the 1-minute load average is at least 0.5. For a daemon the API can't see, `touch ~/.sandboxer/keep-awake`. The integrated agents (Claude Code, Codex and others) are already installed and can be driven with `sbx prompt` ([Agents](/docs/agents)).

## What's different

What you gain:

- **No 12-hour cap.** Auto-stop goes up to 30 days, or off, on paid plans. The free trial caps it at 8 hours.
- **Stops keep memory.** Auto-stop, idle pause and `sbx stop` save memory and disk, and a resume on a matching machine brings running processes back. GitHub's docs describe a codespace stopping, and our [comparison data](/compare/github-codespaces) found no documented memory-preserving pause.
- **A whole VM.** Root through `sudo`, systemd as PID 1, Docker and nested KVM, instead of a container with limited access to the host.
- **An API for agents.** Run commands, read files and prompt agents over REST, the SDKs or MCP, without an open SSH session.

What you lose or must change:

- **No `devcontainer.json`.** You maintain a setup script and a named snapshot instead.
- **No browser editor per repository.** You connect a local VS Code or Cursor over SSH. The dashboard has a web terminal and a file browser.
- **GitHub integration.** Codespaces opens from a repository page and follows organization policies. Sandboxer connects to GitHub through environments.
- **Free hours.** Codespaces gives personal accounts free monthly usage. Sandboxer's trial lasts 7 days and 25 hours and needs a card.
- **Sizes.** Codespaces goes up to 32 cores and 128 GB. Sandboxer's largest size, `xlarge`, is 16 vCPU and 32 GB, on the $100 plan or higher.
- **Region.** Sandboxer has two regions, us-east (Ashburn, Virginia) and eu-central (Helsinki, Finland); see [regions](/docs/regions). New sandboxes go to the nearest one unless you set `region`.

## Pricing

GitHub's prices are from [Codespaces billing](https://docs.github.com/en/billing/concepts/product-billing/github-codespaces), checked 2026-10-27. Ours are from [/pricing](/pricing).

| | GitHub Codespaces | Sandboxer |
| - | - | - |
| Compute | $0.18/hour for 2 cores, doubling with each step to $2.88/hour for 32 cores | `small` $0.018/hour, `default` $0.036/hour, `large` $0.072/hour |
| 4 cores | $0.36/hour for the 4-core machine | `default` size (4 vCPU, 8 GB): $0.036/hour |
| Storage | $0.07 per GB-month while the codespace exists | Not billed; 50 GB included on the $20 plan |
| Free usage | 120 hours a month (Free) or 180 (Pro) for personal accounts, with an included-usage multiplier equal to the core count | Trial: 7 days and 25 hours, card required |

The two aren't exactly comparable. GitHub's billing page doesn't list RAM for the 4-core machine, and the 2-core machine has 8 GB according to the [overview](https://docs.github.com/en/codespaces/overview). Our `default` size has 8 GB.

Example: an agent box with 4 cores running 8 hours a day for 22 days is 176 hours. On Codespaces that's 176 × $0.36 = $63.36 of compute before storage and free usage. On Sandboxer, `default` costs 176 × $0.036 = $6.34, covered by the $20 plan's included time.

## FAQ

### Does Sandboxer read devcontainer.json?

No. Move `postCreateCommand` and your features into a setup script, then save the result as a named snapshot. Ports become `sbx host` calls, and editor customizations stay in your editor.

### Can an agent run for more than 12 hours?

Yes, on a paid plan. Set `--ttl` up to 30 days, or use `--no-auto-stop`. If auto-stop hits while the agent is working, `sbx resume` brings memory and processes back when it lands on a matching machine.

### Will an idle timeout stop my agent mid-task?

Not while it works. Idle pause waits while a command or agent turn runs, while someone is logged in over SSH, or while the load average is at least 0.5. If it does pause, it keeps memory and wakes on the next API call (if no machine with the same CPU type is free, the wake boots from disk instead: files kept, processes not).

### Can I still use VS Code?

Yes, through Remote-SSH. Run `sbx ssh-config --install`, then connect to `<id>.sbx`. There's no in-browser VS Code.

### Can I run my dev container image?

Docker is preinstalled, so you can pull and run the image inside the sandbox. Most teams install the same tools straight onto the VM in the setup script instead.

## Related

- [Sandboxer vs GitHub Codespaces](/compare/github-codespaces)
- [Quickstart](/docs/quickstart)
- [Long-running tasks](/docs/long-running)
- [SSH from VS Code or Cursor](/guides/ssh-into-a-cloud-sandbox-from-vs-code-or-cursor)
