Create and Manage Azure Managed Disks

The azure-native:compute:Disk resource, part of the Pulumi Azure Native provider, provisions Azure managed disks: their size, storage tier, encryption, and source data. This guide focuses on three capabilities: creating empty disks and disks from snapshots or images, configuring encryption and network access policies, and selecting storage SKUs and zone redundancy.

Disks reference snapshots, images, encryption sets, and disk access resources that must exist separately. The examples are intentionally small. Combine them with your own VM attachments, backup policies, and access controls.

Create an empty disk for data storage

Most deployments start by provisioning an empty disk for VM data storage or application workloads.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Empty,
    },
    diskName: "myDisk",
    diskSizeGB: 200,
    location: "West US",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.EMPTY,
    },
    disk_name="myDisk",
    disk_size_gb=200,
    location="West US",
    resource_group_name="myResourceGroup")
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionEmpty),
			},
			DiskName:          pulumi.String("myDisk"),
			DiskSizeGB:        pulumi.Int(200),
			Location:          pulumi.String("West US"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Empty,
        },
        DiskName = "myDisk",
        DiskSizeGB = 200,
        Location = "West US",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Empty")
                .build())
            .diskName("myDisk")
            .diskSizeGB(200)
            .location("West US")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Empty
      diskName: myDisk
      diskSizeGB: 200
      location: West US
      resourceGroupName: myResourceGroup

The creationData property specifies how the disk is created. Setting createOption to Empty provisions a blank disk. The diskSizeGB property sets the initial capacity. Azure places the disk in the specified location and assigns it a default storage tier based on the SKU.

Copy a disk from an existing snapshot

Teams create disks from snapshots to restore data, clone environments, or provision new VMs with pre-configured state.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Copy,
        sourceResourceId: "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot",
    },
    diskName: "myDisk",
    location: "West US",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.COPY,
        "source_resource_id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot",
    },
    disk_name="myDisk",
    location="West US",
    resource_group_name="myResourceGroup")
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption:     pulumi.String(compute.DiskCreateOptionCopy),
				SourceResourceId: pulumi.String("subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot"),
			},
			DiskName:          pulumi.String("myDisk"),
			Location:          pulumi.String("West US"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Copy,
            SourceResourceId = "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot",
        },
        DiskName = "myDisk",
        Location = "West US",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Copy")
                .sourceResourceId("subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot")
                .build())
            .diskName("myDisk")
            .location("West US")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Copy
        sourceResourceId: subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot
      diskName: myDisk
      location: West US
      resourceGroupName: myResourceGroup

When createOption is Copy, the sourceResourceId points to an existing snapshot. Azure replicates the snapshot’s data into the new disk. The disk inherits the snapshot’s size unless you specify a larger diskSizeGB.

Create a disk from a platform VM image

OS disks are typically created from Azure Marketplace images or custom platform images, providing a bootable disk for VM deployment.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.FromImage,
        imageReference: {
            id: "/Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0",
        },
    },
    diskName: "myDisk",
    location: "West US",
    osType: azure_native.compute.OperatingSystemTypes.Windows,
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.FROM_IMAGE,
        "image_reference": {
            "id": "/Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0",
        },
    },
    disk_name="myDisk",
    location="West US",
    os_type=azure_native.compute.OperatingSystemTypes.WINDOWS,
    resource_group_name="myResourceGroup")
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionFromImage),
				ImageReference: &compute.ImageDiskReferenceArgs{
					Id: pulumi.String("/Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0"),
				},
			},
			DiskName:          pulumi.String("myDisk"),
			Location:          pulumi.String("West US"),
			OsType:            compute.OperatingSystemTypesWindows,
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.FromImage,
            ImageReference = new AzureNative.Compute.Inputs.ImageDiskReferenceArgs
            {
                Id = "/Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0",
            },
        },
        DiskName = "myDisk",
        Location = "West US",
        OsType = AzureNative.Compute.OperatingSystemTypes.Windows,
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import com.pulumi.azurenative.compute.inputs.ImageDiskReferenceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("FromImage")
                .imageReference(ImageDiskReferenceArgs.builder()
                    .id("/Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0")
                    .build())
                .build())
            .diskName("myDisk")
            .location("West US")
            .osType("Windows")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: FromImage
        imageReference:
          id: /Subscriptions/{subscriptionId}/Providers/Microsoft.Compute/Locations/westus/Publishers/{publisher}/ArtifactTypes/VMImage/Offers/{offer}/Skus/{sku}/Versions/1.0.0
      diskName: myDisk
      location: West US
      osType: Windows
      resourceGroupName: myResourceGroup

Setting createOption to FromImage and providing an imageReference creates a disk from a published VM image. The osType property identifies whether the disk contains Windows or Linux. The disk size matches the image unless you specify a larger value.

Encrypt a disk with customer-managed keys

Organizations with compliance requirements encrypt disks using their own keys managed through Azure Key Vault.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Empty,
    },
    diskName: "myDisk",
    diskSizeGB: 200,
    encryption: {
        diskEncryptionSetId: "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
    },
    location: "West US",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.EMPTY,
    },
    disk_name="myDisk",
    disk_size_gb=200,
    encryption={
        "disk_encryption_set_id": "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
    },
    location="West US",
    resource_group_name="myResourceGroup")
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionEmpty),
			},
			DiskName:   pulumi.String("myDisk"),
			DiskSizeGB: pulumi.Int(200),
			Encryption: &compute.EncryptionArgs{
				DiskEncryptionSetId: pulumi.String("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}"),
			},
			Location:          pulumi.String("West US"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Empty,
        },
        DiskName = "myDisk",
        DiskSizeGB = 200,
        Encryption = new AzureNative.Compute.Inputs.EncryptionArgs
        {
            DiskEncryptionSetId = "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}",
        },
        Location = "West US",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import com.pulumi.azurenative.compute.inputs.EncryptionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Empty")
                .build())
            .diskName("myDisk")
            .diskSizeGB(200)
            .encryption(EncryptionArgs.builder()
                .diskEncryptionSetId("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}")
                .build())
            .location("West US")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Empty
      diskName: myDisk
      diskSizeGB: 200
      encryption:
        diskEncryptionSetId: /subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskEncryptionSets/{existing-diskEncryptionSet-name}
      location: West US
      resourceGroupName: myResourceGroup

The encryption property controls data-at-rest encryption. Setting diskEncryptionSetId points to a disk encryption set that wraps your Key Vault key. Azure encrypts all disk data with your key instead of platform-managed keys.

Configure zone-redundant storage for high availability

Production workloads that require protection against datacenter failures use zone-redundant storage to replicate data across availability zones.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Empty,
    },
    diskName: "myDisk",
    diskSizeGB: 200,
    location: "West US",
    resourceGroupName: "myResourceGroup",
    sku: {
        name: azure_native.compute.DiskStorageAccountTypes.Premium_ZRS,
    },
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.EMPTY,
    },
    disk_name="myDisk",
    disk_size_gb=200,
    location="West US",
    resource_group_name="myResourceGroup",
    sku={
        "name": azure_native.compute.DiskStorageAccountTypes.PREMIUM_ZRS,
    })
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionEmpty),
			},
			DiskName:          pulumi.String("myDisk"),
			DiskSizeGB:        pulumi.Int(200),
			Location:          pulumi.String("West US"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
			Sku: &compute.DiskSkuArgs{
				Name: pulumi.String(compute.DiskStorageAccountTypes_Premium_ZRS),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Empty,
        },
        DiskName = "myDisk",
        DiskSizeGB = 200,
        Location = "West US",
        ResourceGroupName = "myResourceGroup",
        Sku = new AzureNative.Compute.Inputs.DiskSkuArgs
        {
            Name = AzureNative.Compute.DiskStorageAccountTypes.Premium_ZRS,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import com.pulumi.azurenative.compute.inputs.DiskSkuArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Empty")
                .build())
            .diskName("myDisk")
            .diskSizeGB(200)
            .location("West US")
            .resourceGroupName("myResourceGroup")
            .sku(DiskSkuArgs.builder()
                .name("Premium_ZRS")
                .build())
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Empty
      diskName: myDisk
      diskSizeGB: 200
      location: West US
      resourceGroupName: myResourceGroup
      sku:
        name: Premium_ZRS

The sku property controls storage type and redundancy. Setting name to Premium_ZRS enables zone-redundant storage, which replicates data synchronously across three availability zones in the region. This protects against datacenter-level failures.

Restrict disk access to private endpoints

Secure environments restrict disk access to private networks by associating disks with a disk access resource.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Empty,
    },
    diskAccessId: "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}",
    diskName: "myDisk",
    diskSizeGB: 200,
    location: "West US",
    networkAccessPolicy: azure_native.compute.NetworkAccessPolicy.AllowPrivate,
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.EMPTY,
    },
    disk_access_id="/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}",
    disk_name="myDisk",
    disk_size_gb=200,
    location="West US",
    network_access_policy=azure_native.compute.NetworkAccessPolicy.ALLOW_PRIVATE,
    resource_group_name="myResourceGroup")
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionEmpty),
			},
			DiskAccessId:        pulumi.String("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}"),
			DiskName:            pulumi.String("myDisk"),
			DiskSizeGB:          pulumi.Int(200),
			Location:            pulumi.String("West US"),
			NetworkAccessPolicy: pulumi.String(compute.NetworkAccessPolicyAllowPrivate),
			ResourceGroupName:   pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Empty,
        },
        DiskAccessId = "/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}",
        DiskName = "myDisk",
        DiskSizeGB = 200,
        Location = "West US",
        NetworkAccessPolicy = AzureNative.Compute.NetworkAccessPolicy.AllowPrivate,
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Empty")
                .build())
            .diskAccessId("/subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}")
            .diskName("myDisk")
            .diskSizeGB(200)
            .location("West US")
            .networkAccessPolicy("AllowPrivate")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Empty
      diskAccessId: /subscriptions/{subscription-id}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/diskAccesses/{existing-diskAccess-name}
      diskName: myDisk
      diskSizeGB: 200
      location: West US
      networkAccessPolicy: AllowPrivate
      resourceGroupName: myResourceGroup

The diskAccessId property links the disk to a disk access resource that controls network exposure. Setting networkAccessPolicy to AllowPrivate blocks public internet access and requires private endpoint connections for disk operations.

Tune IOPS and throughput with Premium v2

High-performance workloads use Premium v2 disks to independently configure IOPS and throughput without being constrained by fixed disk size tiers.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const disk = new azure_native.compute.Disk("disk", {
    creationData: {
        createOption: azure_native.compute.DiskCreateOption.Empty,
    },
    diskIOPSReadWrite: 125,
    diskMBpsReadWrite: 3000,
    diskName: "myPremiumV2Disk",
    diskSizeGB: 200,
    location: "West US",
    resourceGroupName: "myResourceGroup",
    sku: {
        name: azure_native.compute.DiskStorageAccountTypes.PremiumV2_LRS,
    },
});
import pulumi
import pulumi_azure_native as azure_native

disk = azure_native.compute.Disk("disk",
    creation_data={
        "create_option": azure_native.compute.DiskCreateOption.EMPTY,
    },
    disk_iops_read_write=125,
    disk_m_bps_read_write=3000,
    disk_name="myPremiumV2Disk",
    disk_size_gb=200,
    location="West US",
    resource_group_name="myResourceGroup",
    sku={
        "name": azure_native.compute.DiskStorageAccountTypes.PREMIUM_V2_LRS,
    })
package main

import (
	compute "github.com/pulumi/pulumi-azure-native-sdk/compute/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewDisk(ctx, "disk", &compute.DiskArgs{
			CreationData: &compute.CreationDataArgs{
				CreateOption: pulumi.String(compute.DiskCreateOptionEmpty),
			},
			DiskIOPSReadWrite: pulumi.Float64(125),
			DiskMBpsReadWrite: pulumi.Float64(3000),
			DiskName:          pulumi.String("myPremiumV2Disk"),
			DiskSizeGB:        pulumi.Int(200),
			Location:          pulumi.String("West US"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
			Sku: &compute.DiskSkuArgs{
				Name: pulumi.String(compute.DiskStorageAccountTypes_PremiumV2_LRS),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var disk = new AzureNative.Compute.Disk("disk", new()
    {
        CreationData = new AzureNative.Compute.Inputs.CreationDataArgs
        {
            CreateOption = AzureNative.Compute.DiskCreateOption.Empty,
        },
        DiskIOPSReadWrite = 125,
        DiskMBpsReadWrite = 3000,
        DiskName = "myPremiumV2Disk",
        DiskSizeGB = 200,
        Location = "West US",
        ResourceGroupName = "myResourceGroup",
        Sku = new AzureNative.Compute.Inputs.DiskSkuArgs
        {
            Name = AzureNative.Compute.DiskStorageAccountTypes.PremiumV2_LRS,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.compute.Disk;
import com.pulumi.azurenative.compute.DiskArgs;
import com.pulumi.azurenative.compute.inputs.CreationDataArgs;
import com.pulumi.azurenative.compute.inputs.DiskSkuArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var disk = new Disk("disk", DiskArgs.builder()
            .creationData(CreationDataArgs.builder()
                .createOption("Empty")
                .build())
            .diskIOPSReadWrite(125.0)
            .diskMBpsReadWrite(3000.0)
            .diskName("myPremiumV2Disk")
            .diskSizeGB(200)
            .location("West US")
            .resourceGroupName("myResourceGroup")
            .sku(DiskSkuArgs.builder()
                .name("PremiumV2_LRS")
                .build())
            .build());

    }
}
resources:
  disk:
    type: azure-native:compute:Disk
    properties:
      creationData:
        createOption: Empty
      diskIOPSReadWrite: 125
      diskMBpsReadWrite: 3000
      diskName: myPremiumV2Disk
      diskSizeGB: 200
      location: West US
      resourceGroupName: myResourceGroup
      sku:
        name: PremiumV2_LRS

Premium v2 disks decouple performance from capacity. The diskIOPSReadWrite and diskMBpsReadWrite properties let you specify exact IOPS and throughput values. This allows fine-grained performance tuning without oversizing the disk.

Beyond these examples

These snippets focus on specific disk-level features: disk creation from images, snapshots, and empty allocation, encryption with platform-managed and customer-managed keys, storage SKUs and zone redundancy, and network access control and private endpoints. They’re intentionally minimal rather than full storage solutions.

The examples may reference pre-existing infrastructure such as snapshots, platform images, or Azure Compute Gallery images, disk encryption sets and disk access resources, and resource groups and Azure regions. They focus on configuring the disk rather than provisioning everything around it.

To keep things focused, common disk patterns are omitted, including:

  • Disk attachment to VMs (managed through VM resources)
  • Bursting configuration and performance tier adjustments
  • Shared disk configuration (maxShares property)
  • Extended locations and edge zone placement
  • Security profiles for confidential VMs and Trusted Launch
  • Upload workflows and ImportSecure operations

These omissions are intentional: the goal is to illustrate how each disk feature is wired, not provide drop-in storage modules. See the Disk resource reference for all available configuration options.

Let's create and Manage Azure Managed Disks

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Disk Creation & Sources
What properties can't I change after creating a disk?
The following properties are immutable: location, resourceGroupName, diskName, creationData, and extendedLocation. Plan these carefully during initial creation.
What are the different ways to create a disk?

You can create a disk using creationData.createOption:

  • Empty - Create a blank disk (requires diskSizeGB)
  • FromImage - Create from a platform image or gallery image
  • Copy - Copy from an existing disk or snapshot
  • Import - Import from a VHD in blob storage
  • Upload - Upload a VHD (requires uploadSizeBytes)
  • ImportSecure - Import with security data for confidential VMs
  • UploadPreparedSecure - Upload for Trusted Launch VMs
  • CopyFromSanSnapshot - Copy from an Elastic SAN snapshot
How do I create a disk from a snapshot?
Set creationData.createOption to Copy and provide the snapshot resource ID in creationData.sourceResourceId.
How do I import a VHD from blob storage?
Set creationData.createOption to Import and provide the blob URI in creationData.sourceUri. For cross-subscription imports, also set creationData.storageAccountId.
Encryption & Security
What encryption options are available for disks?

You have two main options:

  1. Platform-managed encryption - Default encryption at rest
  2. Customer-managed encryption - Set encryption.diskEncryptionSetId to your disk encryption set

For confidential VMs, use securityProfile.securityType with variants like ConfidentialVM_DiskEncryptedWithCustomerKey.

How do I create a disk for Trusted Launch VMs?
Set securityProfile.securityType to TrustedLaunch. For upload scenarios, use creationData.createOption set to UploadPreparedSecure.
How do I create a confidential VM disk?
Set securityProfile.securityType to a ConfidentialVM variant (e.g., ConfidentialVM_DiskEncryptedWithCustomerKey) and provide securityProfile.secureVMDiskEncryptionSetId.
Performance & Optimization
How do I optimize disk performance?

You have several options:

  • UltraSSD/PremiumV2 - Configure diskIOPSReadWrite and diskMBpsReadWrite for custom performance
  • Bursting - Set burstingEnabled to true (not for Ultra disks)
  • Frequent attach/detach - Set optimizedForFrequentAttach to true if detaching/attaching >5 times/day
  • PerformancePlus - Set creationData.performancePlus to true for upload scenarios
How do I create a PremiumV2 or UltraSSD disk?
Set sku.name to PremiumV2_LRS or UltraSSD_LRS and configure diskIOPSReadWrite and diskMBpsReadWrite for your performance requirements.
How do I create a zone-redundant disk?
Set sku.name to Premium_ZRS or StandardSSD_ZRS for zone-redundant storage.
Networking & Access
How do I control network access to a disk?

Use networkAccessPolicy to control access:

  • AllowAll - Public access (default)
  • AllowPrivate - Private endpoints only (requires diskAccessId)
  • DenyAll - No network access

For private endpoints, set networkAccessPolicy to AllowPrivate and provide diskAccessId with your DiskAccess resource ID.

Resizing & Multi-Attach
Can I resize a disk while it's attached to a VM?
No, resizes are only allowed when the disk is not attached to a running VM. You can only increase disk size, not decrease it.
How do I enable multi-attach for a disk?
Set maxShares to a value greater than 1. This allows the disk to be attached to multiple VMs simultaneously.

Using a different cloud?

Explore storage guides for other cloud providers: