Guide to Using Tart on macOS Apple Silicon: Create and Manage CLI Virtual Machines for CI/CD

Quick start: Run a macOS/Linux VM in 3 commands

Working on M-series chips (M1 through M4), you will find running VirtualBox or VMware Fusion heavy and clunky. Tart solves this neatly, packaging all operations right inside your terminal.

Install Tart via Homebrew:

brew install cirruslabs/cli/tart

Quickly verify the version:

tart --version

Pull a pre-built Ubuntu 22.04 LTS ARM64 image from GitHub Container Registry:

# Pull and name the local VM my-ubuntu-vm
tart clone ghcr.io/cirruslabs/ubuntu:latest my-ubuntu-vm

Start the VM in headless background mode without opening a GUI window:

tart run --no-graphics my-ubuntu-vm &

Wait about 3 to 5 seconds for the VM to acquire an IP address, then SSH directly:

# Get the automatically assigned IP
VM_IP=$(tart ip my-ubuntu-vm)

# Default username and password for Cirrus Labs images: admin / admin
ssh admin@$VM_IP

The VM boots almost instantly. You now have an isolated ARM64 Linux shell ready for work.

In-depth explanation: What is Tart and why is it optimized for Apple Silicon?

If you have ever built an x86 Proxmox homelab to test apps, you know the frustration of needing a native macOS environment. x86 hardware cannot smoothly emulate Apple’s ARM architecture. Tart was created to fill that gap.

Developed by Cirrus Labs, Tart runs directly on macOS’s native Apple Virtualization.framework without any bulky translation layers. VM CPU and RAM map straight to the underlying Apple Silicon hardware. As a result, Linux VMs boot in just 2–3 seconds, while macOS takes around 12–15 seconds, with idle CPU usage staying well below 1%.

OCI-Native architecture: Treating VMs like containers

Tart’s greatest advantage over Vagrant or Parallels lies in its packaging approach:

  • Container registry packaging: The entire virtual disk (disk.img) and configuration (config.json) are pushed to OCI-compliant registries like GHCR, AWS ECR, or Docker Hub. You pull and push VMs just like you would with docker pull.
  • Instant cloning with APFS: macOS uses APFS with Copy-on-Write (CoW). Running tart clone on a 60GB VM takes a mere 300ms. Physical data is not duplicated until new files are written.

Core operational commands

Common commands used in daily workflows:

# List existing virtual machines
tart list

# Inspect allocated resources (CPU, RAM, disk size)
tart get my-ubuntu-vm

# Scale configuration up to 4 vCPUs and 8GB RAM
tart set my-ubuntu-vm --cpu 4 --memory 8192

# Gracefully stop the VM
tart stop my-ubuntu-vm

# Delete the VM completely when no longer needed
tart delete my-ubuntu-vm

Advanced: Building CI/CD pipelines with ephemeral virtual machines

Tart is exceptionally useful when setting up self-hosted runners for GitLab Runner or GitHub Actions. Each build job gets a fresh VM, which is completely destroyed after completion, leaving no risk of secret leakage or residual disk clutter.

1. Pull official macOS images

Cirrus Labs provides ready-to-use macOS base images ranging from Monterey to Sequoia:

# Pull the macOS Sonoma base image (~25-30GB download size)
tart clone ghcr.io/cirruslabs/macos-sonoma-base:latest macos-base

2. Shell script managing build job lifecycle

A production-ready script for CI runners to provision temporary VMs, run tests, and clean up automatically:

#!/usr/bin/env bash
set -euo pipefail

BASE_IMAGE="macos-base"
BUILD_ID="job-$$"

echo "[1/4] Clone ephemeral VM from snapshot: $BUILD_ID"
tart clone "$BASE_IMAGE" "$BUILD_ID"

echo "[2/4] Starting headless VM..."
tart run --no-graphics "$BUILD_ID" &

# Polling until VM gets an IP (up to 30s)
echo "[3/4] Waiting for IP from DHCP..."
VM_IP=""
for i in {1..30}; do
    VM_IP=$(tart ip "$BUILD_ID" 2>/dev/null || true)
    if [ -n "$VM_IP" ]; then break; fi
    sleep 1
done

if [ -z "$VM_IP" ]; then
    echo "Error: Failed to obtain IP after 30s!"
    tart stop "$BUILD_ID" && tart delete "$BUILD_ID"
    exit 1
fi

echo "VM ready at $VM_IP. Running build tasks..."
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 admin@"$VM_IP" << 'EOF'
    sw_vers
    xcodebuild -version
    # Insert test execution or app build commands here
EOF

echo "[4/4] Cleaning up VM..."
tart stop "$BUILD_ID"
tart delete "$BUILD_ID"
echo "Cleanup complete."

3. Sharing directories via VirtioFS

There is no need to use rsync or scp to copy multi-gigabyte repositories into the VM. Tart comes with built-in VirtioFS support, delivering read/write performance reaching roughly 80-90% of native NVMe speeds:

# Mount project directory from host into the VM
tart run --dir=workspace:/Users/admin/my-project my-ubuntu-vm

Inside the Linux guest OS, mount the share into the filesystem hierarchy:

sudo mkdir -p /mnt/workspace
sudo mount -t virtiofs workspace /mnt/workspace

Practical tips from running Tart in production

  • 2 macOS VM limit: Apple’s Software License Agreement (EULA) restricts each Mac to running a maximum of 2 concurrent macOS virtual machines. Launching more than 2 macOS VMs triggers an error from the virtualization framework.
  • Managing disk bloat: While CoW enables near-instant cloning, Xcode builds generating tens of gigabytes in DerivedData will still consume host disk space. Periodically run tart list to find and purge orphaned VMs.
  • Proper resource allocation: On a 16GB RAM Mac, assign at most 8GB RAM to a VM. macOS requires at least 6–8GB RAM to keep WindowServer, swap cache, and background system tasks running smoothly.
  • Mitigating IP delays: After booting, the virtual network adapter may take 3 to 8 seconds to obtain a DHCP lease from the host bridge. Always implement a polling loop with a timeout rather than relying on a static sleep.
Share: