VM Lifecycle
Understand the states a VM passes through from creation to deletion, including suspend, stop, and snapshot.
VMs default to sticky persistence, which means they will be automatically cleaned up when they aren't running. If you need a VM to persist indefinitely, set persistence: { type: "persistent" } when creating it. See Persistence for details on all persistence types and what they mean.
State Transitions
VMs move between three active states. Suspended VMs resume instantly with full memory intact. Stopped VMs lose memory and boot fresh — only use stop() when you need a reboot.
Snapshots
Any active state can be snapshotted or deleted. With recreate enabled, deleted VMs and snapshots are automatically rebuilt when needed.
States
Running
The VM is actively executing, consuming CPU and memory. This is the state a VM enters immediately after create().
import { freestyle } from "freestyle";
const { vm } = await freestyle.vms.create();
// VM is now running
await vm.exec("echo 'hello'");Suspended
The VM's full memory and CPU state is saved to disk, then the VM is paused. When resumed, it continues from the exact point it left off — no reboot, no lost state.
Suspension happens either explicitly or automatically via idle timeout:
// Explicit suspend
await vm.suspend();
// Auto-suspend after 5 minutes of network inactivity
const { vm } = await freestyle.vms.create({
idleTimeoutSeconds: 300,
});While suspended you are not billed for CPU or memory — only storage.
A suspended VM resumes automatically on:
- Calling
vm.start() - Incoming network activity (e.g. an HTTP request to a mapped port)
- An SSH connection
- Running a command with
vm.exec()
// Explicitly resume
await vm.start();Stopped
The VM is shut down gracefully (like powering off a machine). The disk is preserved but memory state is lost. On next start(), the VM boots fresh from its disk. Most of the time you should use suspend() instead — stop() is only needed when you explicitly want a full reboot.
await vm.stop();
// Later — boots from disk
await vm.start();Killed
For cases where you need to force-terminate a VM immediately without a graceful shutdown:
await vm.kill();Suspend vs Stop
| Suspend | Stop | |
|---|---|---|
| Memory state | Preserved — resumes exactly where it left off | Lost — boots fresh from disk |
| Resume speed | Under 100ms | Full boot (3–7 seconds) |
| Billing | Storage only | Storage only |
| Use case | Almost everything — the default way to pause a VM | Only when you explicitly want a full reboot |
| Auto trigger | Idle timeout | — |
Suspend is almost always what you want. It's faster, preserves state, and costs the same as stop. The only reason to use stop() is when you explicitly need to reboot the VM — for example to reset a corrupted process tree.
Snapshots
A snapshot captures the entire VM state (memory, disk, CPU registers) as an immutable image. Snapshots can be taken from any state — running, suspended, or stopped.
const { snapshotId } = await vm.snapshot();
// Create new VMs from the snapshot
const { vm: clone1 } = await freestyle.vms.create({ snapshotId });
const { vm: clone2 } = await freestyle.vms.create({ snapshotId });Snapshots are replicated across the network for fast creation anywhere. See Specs and Snapshots for declarative snapshot creation and layering.
Forking
A running VM can be forked without noticeably pausing the original. This creates a new VM that is an exact copy of the current state.
const { vm: forked } = await vm.fork();Use forking when you need one-off copies for parallel exploration. Use snapshots when you need a reusable base image.
Idle Timeout
Automatically suspend VMs after a period of network inactivity (default: 300 seconds):
const { vm } = await freestyle.vms.create({
idleTimeoutSeconds: 600, // 10 minutes
});Set to null to disable idle timeout:
const { vm } = await freestyle.vms.create({
idleTimeoutSeconds: null, // Never auto-suspend
});Cost consideration: VMs with no idle timeout continue running (and billing) indefinitely. Use persistence settings to control storage costs when suspended.
Deletion
Delete a VM to permanently remove it and free all resources:
await freestyle.vms.delete({ vmId });Waiting for Exit
If a VM is running a finite workload, you can block until it exits:
const result = await vm.waitForExit();Common Patterns
Development VM with long timeout
const { vm } = await freestyle.vms.create({
workdir: "/workspace",
idleTimeoutSeconds: 3600, // 1 hour
gitRepos: [
{ repo: repoId, path: "/workspace" },
],
});Production VM (never suspend)
const { vm } = await freestyle.vms.create({
idleTimeoutSeconds: null,
persistence: { type: "persistent" },
waitForReadySignal: true,
});Serverless-style VM
const { vm } = await freestyle.vms.create({
recreate: true,
idleTimeoutSeconds: 60, // Suspend quickly
persistence: { type: "ephemeral" },
});