Menu

Go SDK — VMs

Virtual machines use ComputeServiceClient and SSHKeysServiceClient. Create returns an operation — poll until SUCCEEDED. Configure clients per Go SDK → Configure.

VM manifest

CreateVirtualMachine takes a VirtualMachineManifest — the same schema the CLI flags and YAML manifests map to.

metadata

FieldRequiredDescription
nameNoHostname (DNS label, ≤63 chars).
projectYes*projects/{slug}
labels / annotationsNoMetadata maps.

spec.region

Required. e.g. datacenters/us-dal-1.

spec.compute

FieldDescription
cpuClasscascadelake, milan, etc.
vcpus1–64
ramGibRAM in GiB
gpu.model / gpu.countWhole-GPU passthrough, e.g. rtx4090

spec.boot

Exactly one of image, imageUrl, or diskName.

FieldDescription
imageCatalog id, e.g. ubuntu-24-04
diskGibBoot disk size with image/imageUrl
diskNameExisting disk as boot volume

spec.network

FieldDefaultDescription
publicIpv4falseOpt-in public IPv4 (~$2/mo). IPv6 always on.
networkautoTenant network; empty → default in DC.

spec.users[]

FieldDescription
nameLogin user (not root)
sshKeysRegistered key resource names
sshPubkeyInline public key line
passwordConsole login password

If cloudInit is set on spec, it replaces generated user config.

spec.billing

BILLING_MODE_HOURLY (default) or BILLING_MODE_MONTHLY_1 through BILLING_MODE_MONTHLY_12. Prepaid terms debit wallet at create.

Create a VM

resp, err := compute.CreateVirtualMachine(ctx, connect.NewRequest(
    &computev1.CreateVirtualMachineRequest{
        Manifest: &computev1.VirtualMachineManifest{
            ApiVersion: "compute.metalhost.io/v1",
            Kind:       "VirtualMachine",
            Metadata: &computev1.VirtualMachineMetadata{
                Name: "web-1", Project: "projects/my-app",
            },
            Spec: &computev1.VirtualMachineSpec{
                Region: "datacenters/us-dal-1",
                Compute: &computev1.VMComputeSpec{
                    CpuClass: "cascadelake", Vcpus: 2, RamGib: 8,
                },
                Boot:    &computev1.VMBootSpec{Image: "ubuntu-24-04", DiskGib: 80},
                Network: &computev1.VMNetworkSpec{PublicIpv4: true},
                Users: []*computev1.UserSpec{{
                    Name: "ubuntu",
                    SshKeys: []string{"projects/my-app/ssh-keys/laptop"},
                }},
            },
        },
    },
))
opName := resp.Msg.GetOperation().GetName()

Poll opName with OperationsService/GetOperation. On success, metadata.virtual_machine_name is the full VM name.

Quote before create

catalog := catalogv1connect.NewCatalogServiceClient(httpClient, base)
resp, err := catalog.QuoteVirtualMachine(ctx, connect.NewRequest(
    &catalogv1.QuoteVirtualMachineRequest{
        Vcpus: 2, RamGib: 8, CpuClass: "cascadelake", BootDiskGib: 80,
        AssignPublicIpv4: true,
    },
))

SSH keys

Separate client — register before create:

keys := computev1connect.NewSSHKeysServiceClient(httpClient, base)
_, err := keys.CreateSSHKey(ctx, connect.NewRequest(&computev1.CreateSSHKeyRequest{
    ProjectName: "projects/my-app",
    SshKeyId:    "laptop",
    DisplayName: "Laptop",
    PublicKey:   "ssh-ed25519 AAAA... user@host",
}))

List and get

list, _ := compute.ListVirtualMachines(ctx, connect.NewRequest(
    &computev1.ListVirtualMachinesRequest{ProjectName: project, PageSize: 100},
))
one, _ := compute.GetVirtualMachine(ctx, connect.NewRequest(
    &computev1.GetVirtualMachineRequest{Name: vm},
))

Lifecycle

Delete, resize, and clone also return operations:

vm := "projects/my-app/virtual-machines/web-1"
compute.StopVirtualMachine(ctx, connect.NewRequest(&computev1.StopVirtualMachineRequest{Name: vm}))
compute.StartVirtualMachine(ctx, connect.NewRequest(&computev1.StartVirtualMachineRequest{Name: vm}))
compute.RestartVirtualMachine(ctx, connect.NewRequest(&computev1.RestartVirtualMachineRequest{Name: vm}))
compute.ResizeVirtualMachine(ctx, connect.NewRequest(&computev1.ResizeVirtualMachineRequest{
    Name: vm, Vcpus: 4, RamGib: 16, CpuClass: "cascadelake",
}))
compute.DeleteVirtualMachine(ctx, connect.NewRequest(&computev1.DeleteVirtualMachineRequest{Name: vm}))

Snapshots and clone

compute.CreateVMSnapshot(ctx, connect.NewRequest(&computev1.CreateVMSnapshotRequest{
    VirtualMachineName: vm,
    DisplayName:        "pre-upgrade",
}))
compute.CloneVirtualMachine(ctx, connect.NewRequest(&computev1.CloneVirtualMachineRequest{
    SourceName:  vm,
    DisplayName: "web-1-copy",
}))

Console

OpenConsole returns a short-lived URL for in-browser serial/VNC access — same RPC the dashboard console uses.

What's next