Specs and Snapshots
Use specs and snapshots to create similar VMs quickly.
What is a VmSpec?
A VmSpec is a declarative configuration that defines how to set up a VM. Specs can include:
- Files - Add files to the filesystem
- Git repositories - Clone repos into the VM
- Systemd services - Define background services and startup tasks
- Users and groups - Create system users with specific permissions
- Environment variables - Set environment configuration
Specs can be used directly to create a VM, or used as snapshot layers to enable caching.
Quick Start
import { freestyle, VmSpec } from "freestyle-sandboxes";
const spec = new VmSpec({
// Add files to the VM
additionalFiles: {
"/tmp/hello-world.txt": {
content: "Hello World!"
}
},
// Clone a git repository
gitRepos: [{
repo: "https://github.com/owner/repo",
path: "/app"
}],
// Define systemd services
systemd: {
services: [{
name: "my-app",
mode: "service",
exec: ["npm start"],
workdir: "/app"
}]
}
});
// Create a VM directly from the spec
const { vm } = await freestyle.vms.create({ spec });What is a snapshot?
A snapshot is an immutable saved state of a VM, including its memory, disk, and CPU registers. Once created, snapshots are replicated across our network for fast VM creation anywhere. You can create snapshots in two ways:
1. Snapshot an existing VM
Call snapshot() on any VM (running, suspended, or stopped). Running/suspended VMs create "live" snapshots that resume instantly.
import { freestyle } from "freestyle-sandboxes";
const { vm } = await freestyle.vms.create();
// Set up the VM
await vm.exec("apt-get update && apt-get install -y nginx");
await vm.fs.writeTextFile("/etc/nginx/sites-available/default", nginxConfig);
// Create a reusable snapshot
const { snapshotId } = await vm.snapshot();Tip: If you just need copies of the current VM for parallel work, use
vm.fork()instead. It's faster for one-time duplication but doesn't create a reusable snapshot.
2. Create a snapshot declaratively with VmSpec
Use VmSpec to define your VM configuration, then pass it as a snapshot layer to cache it. Calling with the same snapshot spec returns the cached snapshot instantly.
const spec = new VmSpec({
gitRepos: [{
repo: "owner/my-app",
path: "/app"
}],
additionalFiles: {
"/app/.env": {
content: "NODE_ENV=production"
}
},
systemd: {
services: [{
name: "install-deps",
mode: "oneshot",
exec: ["npm install"],
workdir: "/app",
wantedBy: ["multi-user.target"]
}]
}
});
// First call builds and caches
const { vm } = await freestyle.vms.create({ snapshot: spec });
// Second call returns cached snapshot immediately
const { vm: vm2 } = await freestyle.vms.create({ snapshot: spec });Using snapshots and specs
From a snapshot ID
const { vm } = await freestyle.vms.create({
snapshotId,
});Directly from a spec (no caching)
Pass the spec directly to freestyle.vms.create() to apply configuration without caching.
const { vm } = await freestyle.vms.create({
spec,
});Retrieving VMs with typed helpers
When you add integrations via with, the returned vm includes typed helper properties (for example vm.js, vm.python). To get those helpers back later, pass the same spec to vms.get() or vms.ref().
import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmNodeJs } from "@freestyle-sh/with-nodejs";
const spec = new VmSpec({
with: {
js: new VmNodeJs(),
},
});
const { vmId, vm } = await freestyle.vms.create({ spec });
await vm.js.runCode("console.log('hello')");
// Later: retrieve by id with helpers restored
const { vm: loaded } = await freestyle.vms.get({ vmId, spec });
await loaded.js.runCode("console.log('hello again')");
// Or create a local reference without an API call
const ref = freestyle.vms.ref({ vmId, spec });
await ref.js.runCode("console.log('hello from ref')");Layering additional configuration
Apply extra configuration on top of a snapshot by passing additional options to freestyle.vms.create(). These settings are not cached.
const { vm } = await freestyle.vms.create({
snapshot: spec, // or snapshotId
additionalFiles: {
"/tmp/goodbye-world.txt": {
content: "Goodbye World!"
}
},
env: {
API_KEY: "secret-key"
}
});Building layered specs
Create reusable base specs and extend them for specific use cases. Snapshot layers are cached; outer layers are applied on top.
Base spec with a snapshot
const layer1 = new VmSpec({
additionalFiles: {
"/opt/layer-1.txt": {
content: "layer 1 data"
}
},
});
const layer2 = new VmSpec({
snapshot: layer1,
additionalFiles: {
"/opt/layer-2.txt": {
content: "layer 2 data"
}
},
});