LogoFreestyle

VM Configuration

Configure filesystem size, timeouts, working directory, and more.

Root Filesystem Size

Control the size of the VM's root filesystem (default: 16000 MB):

import { freestyle, VmTemplate } from "freestyle-sandboxes";

const template = new VmTemplate({
  rootfsSizeMb: 32000, // 32 GB
});

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

The filesystem uses ext4 and can be resized after creation:

await vm.resize({ sizeMb: 64000 }); // Resize to 64 GB

Note: You can only increase the size, not decrease it.

Working Directory

Set the default directory for commands and file operations:

const { vm } = await freestyle.vms.create({
  workdir: "/app",
  gitRepos: [
    { repo: "https://github.com/owner/repo", path: "/app" },
  ],
});

// Commands run in /app by default
await vm.exec("npm install"); // Runs in /app
await vm.exec("ls"); // Lists /app contents

Without a working directory, commands run in /root:

const { vm } = await freestyle.vms.create();
await vm.exec("pwd"); // Output: /root

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 persistent or sticky storage to preserve state while allowing suspension.

Ready Signals

Control when the VM creation API call returns by waiting for the VM to be fully ready:

const { vm } = await freestyle.vms.create({
  waitForReadySignal: true,
  readySignalTimeoutSeconds: 120, // Default: 120 seconds
});

By default (waitForReadySignal: false), the API returns as soon as the serial console shows the login prompt. This typically takes 1-2 seconds.

When waitForReadySignal: true, the API waits for the serial console to reach the login prompt before returning. This ensures the VM is fully booted and ready to accept commands.

Note: In the future, this will be configurable to wait for custom readiness conditions like systemd service health checks or application-specific signals.

Recreate

Allow the VM to be recreated automatically if deleted:

const { vm, vmId } = await freestyle.vms.create({
  recreate: true,
  gitRepos: [
    { repo: "https://github.com/owner/repo", path: "/app" },
  ],
});

// Delete the VM
await freestyle.vms.delete({ vmId });

// The VM can be recreated with the same ID and configuration
const recreated = await vm.start(); // Automatically recreates

This is useful for:

  • Serverless-style workloads
  • Cost optimization (delete when not in use)
  • Automatic recovery from failures

Additional Files

Add files to the VM filesystem:

const { vm } = await freestyle.vms.create({
  additionalFiles: {
    "/app/config.json": {
      content: JSON.stringify({ apiKey: "secret" }),
    },
    "/etc/app/settings.conf": {
      content: "debug=true\nport=3000",
    },
  },
});

Binary Files

Use base64 encoding for binary files:

additionalFiles: {
  "/app/image.png": {
    content: "iVBORw0KGgoAAAANSUhEUgA...", // Base64 encoded
    encoding: "base64",
  },
}

Large Files

For large files, consider:

  1. Using git repositories
  2. Downloading during VM startup
  3. Using external storage
systemd: {
  services: [
    {
      name: "download-assets",
      mode: "oneshot",
      exec: ["curl -o /app/data.zip https://example.com/data.zip"],
      wantedBy: ["multi-user.target"],
    },
  ],
}

Template vs Direct Configuration

Most configuration options can be used in two ways:

const template = new VmTemplate({
  rootfsSizeMb: 32000,
  workdir: "/app",
  gitRepos: [
    { repo: "owner/repo", path: "/app" },
  ],
  additionalFiles: {
    "/app/.env": { content: "NODE_ENV=production" },
  },
});

// Cached after first creation
const { vm } = await freestyle.vms.create({ template });

Directly (applied on top of template/snapshot)

const { vm } = await freestyle.vms.create({
  template, // Base configuration
  // These are applied after the template
  additionalFiles: {
    "/app/custom.txt": { content: "custom content" },
  },
  workdir: "/custom", // Overrides template workdir
  idleTimeoutSeconds: 600,
});

Combining Options

A complete example combining multiple configuration options:

import { freestyle, VmTemplate } from "freestyle-sandboxes";

const template = new VmTemplate({
  rootfsSizeMb: 32000,
  workdir: "/app",
  gitRepos: [
    {
      repo: "https://github.com/owner/webapp",
      path: "/app",
      rev: "main",
    },
  ],
  additionalFiles: {
    "/app/.env.production": {
      content: "DATABASE_URL=...\nAPI_KEY=...",
    },
  },
  systemd: {
    services: [
      {
        name: "install-deps",
        mode: "oneshot",
        exec: ["npm install"],
        workdir: "/app",
        after: ["freestyle-git-sync.service"],
        wantedBy: ["multi-user.target"],
      },
      {
        name: "web-server",
        mode: "service",
        exec: ["npm start"],
        workdir: "/app",
        after: ["install-deps.service"],
        env: {
          PORT: "3000",
          NODE_ENV: "production",
        },
      },
    ],
  },
});

const { vm, domains } = await freestyle.vms.create({
  template,
  ports: [
    { port: 443, targetPort: 3000 },
  ],
  idleTimeoutSeconds: 600,
  persistence: {
    type: "ephemeral",
    deleteEvent: "OnSuspend",
  },
});

console.log(`App: https://${domains[0]}`);

Best Practices

Use templates for static configuration

Put configuration that doesn't change between VMs in templates:

  • Git repositories
  • System dependencies
  • Base files
  • Systemd services

Keep dynamic config outside templates

Apply per-VM configuration directly:

  • Secrets/API keys
  • Environment-specific settings
  • Port mappings
  • Persistence settings

Example: Staging vs Production

const baseTemplate = new VmTemplate({
  gitRepos: [{ repo: "https://github.com/owner/app", path: "/app" }],
  systemd: { /* ... */ },
});

// Staging
const { vm: staging } = await freestyle.vms.create({
  template: baseTemplate,
  additionalFiles: {
    "/app/.env": { content: "ENV=staging\nAPI_URL=..." },
  },
  idleTimeoutSeconds: 300, // Suspend quickly
});

// Production
const { vm: prod } = await freestyle.vms.create({
  template: baseTemplate,
  additionalFiles: {
    "/app/.env": { content: "ENV=production\nAPI_URL=..." },
  },
  persistence: { type: "persistent" },
  idleTimeoutSeconds: null, // Never suspend
});

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.