Skip to content

feat(vercel-sandbox,sandbox): introduce keepLast parameters for SDK/CLI (under feature flag)#164

Draft
marc-vercel wants to merge 2 commits intonamed-sandboxesfrom
named-sandboxes-keep-last
Draft

feat(vercel-sandbox,sandbox): introduce keepLast parameters for SDK/CLI (under feature flag)#164
marc-vercel wants to merge 2 commits intonamed-sandboxesfrom
named-sandboxes-keep-last

Conversation

@marc-vercel
Copy link
Copy Markdown
Collaborator

@marc-vercel marc-vercel commented Apr 23, 2026

Introduce keepLast snapshot retention and forceDelete for the SDK and CLI. These changes are gated behind a feature flag until we agree that this is the correct contract.

CLI

sandbox create and the new sandbox config keep-last subcommand configure a retention policy that keeps only the N most recent snapshots. By default, evicted snapshots are deleted immediately; pass --soft-evict to let them fall back to the sandbox's default expiration instead.

> sandbox create --keep-last 3
> sandbox create --keep-last 3 --keep-last-for 7d
> sandbox create --keep-last 5 --keep-last-for 30d --soft-evict

> sandbox config keep-last my-sandbox 3
> sandbox config keep-last my-sandbox 3 --for 7d --soft-evict
> sandbox config keep-last my-sandbox --clear
> sandbox config list my-sandbox     # includes a new "Keep last" row

sandbox snapshots delete supports --force / -f to delete a snapshot that is currently the sandbox's currentSnapshotId (server rejects the delete without it when the flag is on):

> sandbox snapshots delete snap_abc            # fails if the snapshot is in use
> sandbox snapshots delete snap_abc --force    # succeeds

SDK

Sandbox.create and Sandbox.update accept a new optional snapshotKeepLast field.

const sandbox = await Sandbox.create({
  snapshotKeepLast: {
    count: 3,
    expiration: 7 * 24 * 60 * 60 * 1000,   // ms, 0 = never. Falls back to snapshotExpiration when omitted.
    deleteEvicted: true,                    // default true
  },
});

On Sandbox.update, pass null to remove the policy:

await sandbox.update({ snapshotKeepLast: null });

snapshot.delete accepts forceDelete to bypass the server's in-use check where we fail if the latest snapshot is being used by a sandbox (and is the last snapshot):

await snapshot.delete({ forceDelete: true });

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sandbox Ready Ready Preview, Comment, Open in v0 Apr 27, 2026 3:18pm
sandbox-cli Ready Ready Preview, Comment, Open in v0 Apr 27, 2026 3:18pm
sandbox-sdk Ready Ready Preview, Comment, Open in v0 Apr 27, 2026 3:18pm
sandbox-sdk-ai-example Ready Ready Preview, Comment, Open in v0 Apr 27, 2026 3:18pm
workflow-code-runner Ready Ready Preview, Comment, Open in v0 Apr 27, 2026 3:18pm

* on this sandbox, if any.
*/
public get keepLastSnapshots():
| { count: number; expiration?: number; deleteEvicted: boolean }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use SandboxMetaData['keepLastSnapshots'] here and everywhere else where we duplicate the types definition, but I think we should instead extract into its own type (basically everything line 119-134) so we keep the TSDoc everywhere

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants