The devbox code works. It creates machines, writes files, runs the tests your agent generates, and nobody on the team wants to touch it again. Then the sandbox line on the cloud bill gets a closer look, and someone asks how hard it would be to move.
Moving from Runloop to Solari is mostly an import change. Solari ships a compatibility package that exposes the Runloop devbox API on top of Solari sandboxes: install it, change the import, set a Solari API key, and the devbox code stays as it is. A call outside the supported set throws a clear error naming the feature, so gaps surface on the first run instead of in production. This guide follows the Runloop migration docs: what stays the same, what to change, and how to test it.
What Stays the Same
Start with what the migration leaves alone, because it is most of the code. The package exports Runloop's own names, Runloop for the REST layer and RunloopSDK for the object layer (plus the async versions in Python), together with Runloop's error classes.
Devbox lifecycle calls work as written: create (including from a snapshot or a blueprint), fromId, list, getInfo, shutdown, suspend, resume and keepAlive. On Solari, suspend and resume map to pause and resume, which keep memory and disk in the sandbox. Commands through cmd.exec, file reads and writes, and snapshot management carry over too.
Error handling is unchanged as well. A missing devbox still raises NotFoundError, a rate limit still raises RateLimitError, and existing catch blocks keep working. With that baseline clear, the actual change is small.
Install the Package and Change the Import
The first step is the package itself, which comes in TypeScript and Python versions:
Then swap the import line and pass a Solari key. In TypeScript it looks like this:
In Python the change is from solari_runloop import RunloopSDK, and the constructor reads SOLARI_API_KEY from the environment. On the TypeScript side, the package ships only as JavaScript modules, so CommonJS code loads it with a dynamic import(). Once the import resolves, the next thing to get right is which key and which host the client talks to.
Set the Key and the Base URL
Configuration is where the package is strict on purpose. The key comes from the bearerToken option, then SOLARI_API_KEY, then RUNLOOP_API_KEY, but only a Solari key starting slr_ is ever used. A Runloop key left in an environment variable is skipped with a warning and never sent anywhere.
The base URL follows the same order and defaults to Solari's API. Passing any other host explicitly throws, so the Solari key, a bearer token, can never reach Runloop's servers. That leaves the calls that behave a little differently.
What Behaves Differently
Most differences are about how Solari implements a call, not whether it works. The figure below lists the ones worth checking before cutover.

Resource sizes are rounded up to whole vCPUs and capped with a warning, so nothing errors. The snapshotDisk call behaves differently too: it is synchronous and keeps memory as well as disk. Blueprints are the third change, building a Solari template from the common Dockerfile instructions (RUN, ENV, ARG, WORKDIR, ENTRYPOINT, CMD, COPY and ADD), so a multi-stage build needs rewriting first.
Secrets become Solari account secrets, which are write-only: no call returns a value, and they arrive as environment variables at create. Two scoping details sit alongside them: cmd.execAsync and logs work inside the process that started the command, not across processes.
File ownership is the last difference to plan for. Files written through the files API are owned by root while commands run as a non-root account, so a command that writes to such a file may need a chown first. Beyond these, a short list of calls throws on purpose.
What Throws SolariCompatUnsupported
The package fails loudly instead of silently. These calls raise SolariCompatUnsupported, which is an APIError: onEvict, SSH keys, closeStdIn, object mounts, gateways, network policies, agents, axons, MCP configs and any create parameter the package does not know.
Some client options, such as maxRetries, are accepted and have no effect. Those options come from @runloop/api-client 2.0.0, the version the package targets, and Runloop's later 3.0.0 release is next on the list. The full call-by-call matrix ships as COMPAT.md in each package, and it is the right input for the test pass below.
How to Test the Migration
Testing is a short loop, because the package reports its own gaps. Run the hello-world from the docs first: create a devbox, write main.py, run it with cmd.exec, print stdout and the exit code, then shut down. If that passes, the key, the host and the import are right.
Next, run the existing suite against Solari and search the output for SolariCompatUnsupported. Each hit names the feature, so check it against COMPAT.md and decide whether to drop the call or rework it. Watch for warnings too, such as a capped resource size or a skipped Runloop key.
Last, exercise the state paths the agent depends on: suspend and resume a devbox, take a snapshot, create a devbox from it, and delete the snapshot. Deleting a snapshot that still has live children raises ConflictError, a useful check on cleanup order. With those passes green, the cutover is a deploy.
Choosing the Right Setup
The migration comes down to an import, a key and a test pass. Code built on Runloop's core devbox, command, file and snapshot calls moves over unchanged, while code that leans on gateways, network policies or SSH needs a rework that the error will name on the first run. Runloop designed the devbox API this package mirrors; Solari is the younger company and moves faster on speed and price.
Get Started With Solari
Install the compatibility package and run the hello-world devbox on the Free plan, which includes $3 of monthly credits. From there the move pays off in speed and cost: Solari sandboxes are ready in 90 ms, and at list price a sandbox hour costs $0.114 on Solari's Team plan against $0.640 on Runloop (4 vCPU, 8 GB). Read the introduction to Solari, then follow the Runloop migration guide to move your first devbox today.
