Azure
Connect an Azure subscription so Portal can run jobs on Azure VMs, spot or on-demand, and on Azure Container Apps.
Warnings and limits
- One Azure connection runs two routes:
azure(Azure VMs) andaca(Azure Container Apps). Name the one you want where a command takes--providers. - Azure gives a spot VM about 20 s of notice before it evicts it: the Scheduled Events
Preemptnames a time 22 to 27 s out (less than the 30 s Azure documents, measured on 2026-10-31), and Portal's node sees it within about a second. When a job's memory is more than Portal can save in 20 s, its plan says so: keep the state small, or take an on-demand machine or a provider with a longer notice (AWS spot gives 2 minutes). - An Azure VM that shuts down goes on billing until it is deleted. Portal deletes a VM when its lease ends, even while its job still runs; the job's work since its last checkpoint is then lost.
- An Azure VM Azure evicted or deleted is billed to that moment, read from the instance view or from your subscription's activity log (the eviction's time, else the deletion's completion), not to the minute Portal declared the job lost; a checkpoint the eviction cut short is billed the same way. The activity log read needs Reader on the subscription; a connection with Contributor on
somaalone is billed to the declaration, as before (see Connect). - Azure VM quotes check your subscription's vCPU quotas with their usage (the region's total vCPUs and the VM family's for on-demand, the region's low-priority vCPUs for spot) and list an offer that does not fit as unavailable, with the quota named. A quota Portal cannot read leaves the offer unchecked, and Azure refuses a start that would cross a limit with your other VMs, after which Portal tries the next offer. See Quotas and capacity.
- NV sizes (slices of an NVIDIA A10) are not started on hosted Portal: their driver needs a login that Portal's VMs do not allow. Use an NC size.
- Quotes leave out each VM's OS disk (64 GB, 128 GB on GPU sizes), its public IPv4 address and data transfer.
- A Container Apps job runs Portal's node image from a Basic container registry Portal makes in your subscription at your first Container Apps job (resource group
soma, namedportalfollowed by 18 characters), copied there by Azure from Portal's public registry. Azure bills the registry (Basic tier) until you delete it, and Portal makes it again when it is needed. When the copy cannot be made or pulled, the job runs the public image and the copy is tried again 10 minutes later. Container Apps has no spot and runs a replica 24 hours at most. - Azure Container Apps gives no interruption notice: if Azure stops the execution, progress since the job's last checkpoint is lost; Portal parks it only on your suspend, a move or a policy. When Azure stopped an execution on 2026-10-31, the replica was gone 0.55 s later, before Portal's node could checkpoint anything. For that reason
portal interruptis refused on Container Apps: test a job's resilience there withportal suspendorportal move, which take the same checkpoint path. - Azure VMs need the resource providers Microsoft.Compute and Microsoft.Network registered in your subscription, and Container Apps needs Microsoft.App and Microsoft.OperationalInsights.
portal connect azure --from-cliregisters the missing ones, which can take up to 5 minutes; the connection itself cannot. Until they are registered, a VM fails to start and Portal tries the next offer.
Connect
portal connect azure --from-cli--from-cli uses your az login. It prints every step and asks before it makes anything: an app registration with a federated credential for Portal's identity, given Contributor on one resource group, soma, and nothing else. No secret is stored. Choose the subscription with --subscription S and the location with --location L (eastus by default).
To use a client secret instead, add --secret: the secret is sealed on Portal's side and never shown again. The console's Connect page takes either method.
Contributor on soma is all a run needs. One read goes beyond it: when Azure no longer lists a VM, Portal reads your subscription's activity log for that VM to bill it to the moment Azure evicted or deleted it, and that read needs Reader on the subscription (the activity log is the subscription's, not the resource group's). Without it Azure answers AuthorizationFailed, Portal reads nothing, and the VM is billed as before, to the minute Portal declares the job lost; nothing else changes. To grant it: az role assignment create --assignee APP_ID --role Reader --scope /subscriptions/SUBSCRIPTION_ID.
What Portal makes in your subscription
Everything goes in the resource group soma, the one the connection may change:
| For | What | Names |
|---|---|---|
| each VM | the VM, its OS disk, network interface, public IP address, network security group and virtual network | soma-<runtime id>, and the same with -disk, -nic, -ip, -nsg, -vnet |
| Container Apps | one environment, and one job for each run | soma-env, soma-<runtime id> |
Each is tagged soma:managed=true, and a VM's resources also soma:runtime=<runtime id>. Portal deletes only what carries the tags of the machine it ends. A VM's network security group admits nothing from outside: Portal's node on the VM connects out to Portal.
VM sizes
| Size | vCPUs | Memory | GPU |
|---|---|---|---|
| Standard_D2s_v5 to Standard_D32s_v5, Standard_D2s_v4 to Standard_D32s_v4 | 2 to 32 | 4 GiB per vCPU | none |
| Standard_NC4as_T4_v3, Standard_NC8as_T4_v3, Standard_NC16as_T4_v3 | 4 to 16 | 28 to 110 GiB | NVIDIA T4 |
| Standard_NC24ads_A100_v4 | 24 | 220 GiB | NVIDIA A100 80 GB |
| Standard_NC40ads_H100_v5 | 40 | 320 GiB | NVIDIA H100 NVL |
Each size is offered spot and on-demand, in your connection's location or the regions a run names, at the prices of Azure's Retail Prices API.
Container Apps sizes
| Size | vCPUs | Memory | GPU |
|---|---|---|---|
| CPU | 1 to 4, in steps of 0.25 | 2 GiB per vCPU | none |
| T4 | 8 | 56 GiB | NVIDIA T4 |
| A100 | 24 | 220 GiB | NVIDIA A100 80 GB |
Naming Azure in commands
The connection is azure. Its VMs' route is azure, and Container Apps' route is aca:
portal prices --providers azure
portal run train.py --cpus 2 --providers azure
portal run train.py --on azure:Standard_D4s_v5:spot
portal prices --providers acaStops and lifetime
A spot VM gets Azure's Scheduled Events notice about 20 s before Azure evicts it: the event names a time 22 to 27 s out, the eviction follows a few seconds after that, and the eviction deletes the VM. Portal's node polls the events every second and is not held up by an answer Azure delays, so it has the whole notice to checkpoint the job and suspend it. Portal counts 20 s when it sizes what the notice can save; a job with more state than that is warned in its plan: keep the state small, or take an on-demand machine or a provider with a longer notice.
A VM runs under a lease that Portal keeps an hour ahead while the job is healthy. At the lease's end the VM shuts itself down, and Portal deletes it within a few minutes, since a VM that is only shut down still bills.
Container Apps can stop a replica, for example when it moves workloads between hosts, and gives no interruption notice: when Azure stopped an execution on 2026-10-31, the replica was gone 0.55 s later, before Portal's node could checkpoint anything. If Azure stops the execution, progress since the job's last checkpoint is lost; Portal parks a Container Apps job only on your suspend, a move or a policy. Every Container Apps quote, the plan that chooses one and the job's events when it lands there say so. For the same reason portal interrupt is refused on Container Apps: test a job's resilience there with portal suspend or portal move, which take the same checkpoint path. A replica also has a fixed limit of 24 hours, and Portal's lifetime policy checkpoints and suspends the job 30 minutes before it.