New APIs in the Virtualization framework and companion frameworks (Accessory Access, DiskImageKit, vmnet) let developers automate macOS guest provisioning, attach USB devices to VMs, configure advanced network topologies, and manage disk images efficiently.
• Automate full macOS VM setup—user account creation, auto-login, and SSH—with a single API call instead of manual Setup Assistant navigation
• Accessory Access framework enables hot-plugging USB devices into running VMs while keeping users in explicit control of their hardware
• DiskImageKit + ASIF support brings sparse disk images and cheap overlay snapshots, slashing storage costs for VM-based CI/CD pipelines
Demonstrates how to boot a new macOS virtual machine and automatically configure a user account, enable auto-login, and turn on SSH remote login using the new VZMacGuestProvisioningOptions API — no manual Setup Assistant interaction required.
import Virtualization
import Foundation
// MARK: - macOS Guest Provisioning (new in macOS 26)
func startProvisionedMacVM(virtualMachine: VZVirtualMachine) async throws {
// 1. Build provisioning options for the first boot
let provisioningOptions = VZMacGuestProvisioningOptions()
provisioningOptions.fullName = "Jane Appleseed"
provisioningOptions.userName = "jappleseed"
provisioningOptions.password = ProcessInfo.processInfo.environment["VM_PASSWORD"] ?? "changeme"
provisioningOptions.isAutoLoginEnabled = true
provisioningOptions.isRemoteLoginEnabled = true // enables SSH
// 2. Attach provisioning options to start options
let startOptions = VZMacOSVirtualMachineStartOptions()
startOptions.guestProvisioning = provisioningOptions
// 3. Start the VM — Setup Assistant will run headlessly on first boot
try await virtualMachine.start(options: startOptions)
print("VM started; guest will auto-provision user '\(provisioningOptions.userName)'")
}
// MARK: - Minimal VM configuration helper (macOS guest)
func buildMinimalMacVMConfiguration(bundleURL: URL) throws -> VZVirtualMachineConfiguration {
let config = VZVirtualMachineConfiguration()
// Load auxiliary storage created during macOS installation
let auxStorageURL = bundleURL.appendingPathComponent("AuxiliaryStorage")
let macPlatform = VZMacPlatformConfiguration()
macPlatform.auxiliaryStorage = try VZMacAuxiliaryStorage(contentsOf: auxStorageURL)
// Load hardware model & machine identifier saved at install time
let hwModelData = try Data(contentsOf: bundleURL.appendingPathComponent("HardwareModel"))
macPlatform.hardwareModel = VZMacHardwareModel(dataRepresentation: hwModelData)!
let machineIDData = try Data(contentsOf: bundleURL.appendingPathComponent("MachineIdentifier"))
macPlatform.machineIdentifier = VZMacMachineIdentifier(dataRepresentation: machineIDData)!
config.platform = macPlatform
// Boot loader
config.bootLoader = VZMacOSBootLoader()
// CPU & memory
config.cpuCount = 4
config.memorySize = 8 * 1024 * 1024 * 1024 // 8 GB
// Disk
let diskURL = bundleURL.appendingPathComponent("Disk.img")
let diskAttachment = try VZDiskImageStorageDeviceAttachment(url: diskURL, readOnly: false)
config.storageDevices = [VZVirtioBlockDeviceConfiguration(attachment: diskAttachment)]
// Network (basic NAT)
let networkDevice = VZVirtioNetworkDeviceConfiguration()
networkDevice.attachment = VZNATNetworkDeviceAttachment()
config.networkDevices = [networkDevice]
try config.validate()
return config
}
// MARK: - Usage example
func runDemo() async {
let bundleURL = URL(fileURLWithPath: "/Users/me/VMs/MyMac.bundle")
do {
let config = try buildMinimalMacVMConfiguration(bundleURL: bundleURL)
let vm = VZVirtualMachine(configuration: config)
try await startProvisionedMacVM(virtualMachine: vm)
} catch {
print("VM provisioning failed: \(error)")
}
}Guest provisioning options are silently ignored if a user account already exists in the guest — they only apply on first boot. Passwords should be sourced from Keychain or environment variables, never hardcoded. vmnet networks are not persisted across app launches; the app must serialize and recreate them. Accessory Access requires the com.apple.developer.accessory-claim entitlement and explicit user consent per device.
macOS only — not available on iOS or iPadOS. Requires Apple Silicon for macOS guest VMs. USB passthrough requires 'Claim USB Accessory' entitlement. DiskImageKit ASIF format requires macOS 26+.
More iOS 27 APIs land every week.
Get notified when new capabilities are published — no noise, just signal.