Templates and Snapshots
Use Templates and snapshots to create similar VMs quickly.
What is a VmTemplate?
A VmTemplate is a declarative configuration that defines how to set up a VM. Templates 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
Templates are automatically cached as snapshots, making subsequent VM creation nearly instant.
Quick Start
import { freestyle, VmTemplate } from "freestyle-sandboxes";
const template = new VmTemplate({
// 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"
}]
}
});
// First call creates and caches the template (~10s)
const { vm } = await freestyle.vms.create({ template });
// Subsequent calls are instant (~100ms)
const { vm: vm2 } = await freestyle.vms.create({ template });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 VmTemplate
Use VmTemplate to define your VM configuration. Freestyle builds the VM, snapshots it, and caches the result. Calling with the same template returns the cached snapshot instantly.
const template = new VmTemplate({
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 { snapshotId } = await freestyle.vms.snapshots.ensure({ template });
// Second call returns cached snapshot immediately
const { snapshotId: cachedId } = await freestyle.vms.snapshots.ensure({ template });
// snapshotId === cachedIdUsing snapshots and templates
From a snapshot ID
const { vm } = await freestyle.vms.create({
snapshotId,
});Directly from a template (recommended)
Pass the template directly to freestyle.vms.create(). Freestyle automatically handles snapshotting and caching.
const { vm } = await freestyle.vms.create({
template,
});Layering additional configuration
Apply extra configuration on top of a snapshot or template without rebuilding. The VM won't reboot—changes are applied instantly.
const { vm } = await freestyle.vms.create({
template, // or snapshotId
additionalFiles: {
"/tmp/goodbye-world.txt": {
content: "Goodbye World!"
}
},
env: {
API_KEY: "secret-key"
}
});Building layered templates
Create reusable base templates and extend them for specific use cases.
Base template with a snapshot
const baseTemplate = new VmTemplate({
snapshotId: "snap-ubuntu-with-docker",
systemd: {
services: [{
name: "docker-compose-up",
mode: "service",
exec: ["docker-compose up"],
workdir: "/app"
}]
}
});Composing templates
// Base: Node.js runtime
const nodeTemplate = new VmTemplate({
additionalFiles: {
"/opt/install-node.sh": {
content: installScript
}
},
systemd: {
services: [{
name: "install-nodejs",
mode: "oneshot",
exec: ["bash /opt/install-node.sh"],
timeoutSec: 300
}]
}
});
// Extended: Node.js + your application
const appTemplate = new VmTemplate({
template: nodeTemplate,
gitRepos: [{
repo: "owner/my-app",
path: "/app"
}],
systemd: {
services: [{
name: "app-server",
mode: "service",
exec: ["npm start"],
workdir: "/app",
after: ["install-nodejs.service"]
}]
}
});This creates two cache layers: one for Node.js (reusable across apps) and one for your specific application.