This guide builds a reusable snapshot with MongoDB already running and ready, then runs real mongosh queries inside a fresh VM — inserting a document and reading it back — without any boot or readiness wait 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 Running MongoDB Database
Create a VM from the minimal base image and install MongoDB with apt-get. The base image is Debian 13 (trixie) and ships nothing extra, so install the prerequisites first, add MongoDB’s official apt repository (its signing key plus a source list), then install the mongodb-org metapackage. MongoDB does not yet publish its server for trixie, so point the source list at the bookworm suite — those packages install cleanly on trixie.
A Freestyle snapshot is a full memory and disk capture, so it preserves a running service and its in-memory state — not just the installed files. So start mongod on the builder and wait until it accepts connections before snapshotting. The mongodb-org package ships a systemd unit named mongod; systemctl start mongod launches it under systemd’s supervision (its own mongodb user, reading /etc/mongod.conf, default bind 127.0.0.1:27017). That command is synchronous and returns the moment systemd has launched the unit, so calling it from vm.exec() is fine. Then poll mongosh until the server answers, snapshot the live machine, and delete the builder. The exec shell is non-login with no HOME and a bare PATH, so call binaries by absolute path (/usr/bin/mongosh).
import { freestyle } from "freestyle";
const { vm: builder } = await freestyle.vms.create();
// Prerequisites for fetching the signing key and the repo.
await builder.exec(
"apt-get update -qq && DEBIAN_FRONTEND=noninteractive " +
"apt-get install -y -qq gnupg curl ca-certificates",
);
// Add MongoDB's signing key and apt source (bookworm suite works on trixie).
await builder.exec(
"curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | " +
"gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg",
);
await builder.exec(
'bash -c \'echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] ' +
'http://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" ' +
"> /etc/apt/sources.list.d/mongodb-org-8.0.list'",
);
// Install the server and the mongosh shell.
const install = await builder.exec(
"apt-get update -qq && DEBIAN_FRONTEND=noninteractive " +
"apt-get install -y -qq mongodb-org",
);
console.log(install.statusCode); // 0
console.log((await builder.exec("/usr/bin/mongod --version")).stdout?.split("\n")[0]); // db version v8.0.23
// Start mongod under systemd and wait until it accepts connections.
await builder.exec("systemctl start mongod");
const ping = "/usr/bin/mongosh --quiet --eval 'db.runCommand({ ping: 1 }).ok'";
let ready = false;
for (let i = 0; i < 30 && !ready; i++) {
await new Promise((r) => setTimeout(r, 1000));
const res = await builder.exec(ping);
ready = res.statusCode === 0 && res.stdout?.trim() === "1";
}
console.log(ready); // true
// Snapshot the live machine — the running, ready server is captured with it.
const { snapshotId } = await builder.snapshot();
await builder.delete();
Query the Running Database
Create a VM from the snapshot. Because the snapshot captured a live, ready mongod, the restored VM comes up with the server already active and accepting connections — there is no systemctl start and no readiness wait. Run one-shot mongosh queries from separate vm.exec() calls; the exec shell is non-login with no HOME and a bare PATH, so call binaries by absolute path (/usr/bin/mongosh).
const { vm } = await freestyle.vms.create({ snapshotId });
// The server is already running from the snapshot — query it immediately.
const mongosh = "/usr/bin/mongosh --quiet --host 127.0.0.1 --port 27017 --eval";
// Insert a document, then read it back.
const insert = await vm.exec(
`${mongosh} 'db.users.insertOne({ name: "Ada", role: "admin" }).acknowledged'`,
);
console.log(insert.stdout?.trim()); // true
const find = await vm.exec(`${mongosh} 'db.users.findOne({ name: "Ada" }).role'`);
console.log(find.stdout?.trim()); // admin
Each exec returns { stdout, stderr, statusCode }, where statusCode of 0 means success. systemd keeps the unit running between calls, so every query hits the same instance and sees the document the previous call inserted.
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 mongod -f\n");
// session.detach() drops your handle — the service keeps running in the VM.