LogoFreestyle

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 === cachedId

Using snapshots and templates

From a snapshot ID

const { vm } = await freestyle.vms.create({
    snapshotId,
});

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.

On this page

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.