This guide builds a reusable snapshot with Redis installed and already running, then creates fresh VMs that serve redis-cli queries instantly — no boot or startup step at runtime.
Install the SDK
pnpm add freestylebun add freestylenpm install freestyleyarn add freestyle Set your API key before calling the API:
export FREESTYLE_API_KEY="your-api-key"
Build a Snapshot with a Redis Key-Value Store Already Running
Create a VM from the minimal base image, install redis-server with apt-get, start the server, and wait until it answers before snapshotting. A Freestyle snapshot is a full memory and disk capture, so it preserves the running Redis process and its in-memory state — not just the installed files. Doing the start and the readiness wait here, on the builder, means the snapshot already contains a live, ready database. Delete the builder VM once the snapshot is captured.
import { freestyle } from "freestyle";
const { vm: builder } = await freestyle.vms.create();
const install = await builder.exec(
"apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq redis-server",
);
console.log(install.statusCode); // 0
// Start the systemd-managed unit on the builder. The command returns immediately;
// systemd supervises the daemon in the background.
await builder.exec("systemctl start redis-server");
// Wait for Redis to accept connections, then snapshot the running server.
let ready = false;
for (let i = 0; i < 15 && !ready; i++) {
await new Promise((r) => setTimeout(r, 1000));
const ping = await builder.exec("redis-cli PING");
ready = ping.stdout?.includes("PONG") ?? false;
}
const { snapshotId } = await builder.snapshot();
await builder.delete();
The Debian package installs Redis as a systemd service named redis-server. Because the snapshot is taken while that unit is active and answering PING, the captured image holds a running, ready server.
Query the Already-Running Server
Create a VM from the snapshot. Because the snapshot captured Redis while it was running and ready, the restored VM comes up with the daemon already active — no systemctl start, no readiness loop. Query it immediately with vm.exec().
const { vm } = await freestyle.vms.create({ snapshotId, idleTimeoutSeconds: null });
// Redis is already up from the snapshot — query it right away.
const ping = await vm.exec("redis-cli PING");
console.log(ping.stdout); // PONG
await vm.exec("redis-cli SET greeting 'hello'");
const get = await vm.exec("redis-cli GET greeting");
console.log(get.stdout); // hello
const incr = await vm.exec("redis-cli INCR counter");
console.log(incr.stdout); // 1
Each exec returns { stdout, stderr, statusCode }, where statusCode of 0 means success. systemd keeps the daemon running between calls, so every query hits the same instance.
Stream the Server’s Logs
vm.exec() buffers a command and only returns once it finishes, so it can’t show a long-running service’s output as it happens. To watch the logs live, open a PTY on the VM — a real terminal streamed over a WebSocket (server-side only, Node 22+) — and follow the unit’s journal. onData delivers the bytes as they arrive:
const session = await vm.pty.open({
cols: 120,
rows: 30,
onData: (bytes) => process.stdout.write(bytes), // live log lines
});
// Follow the service; new lines stream in until you detach.
session.write("journalctl -u redis-server -f\n");
// session.detach() drops your handle — the service keeps running in the VM.