Cost Optimization

    How Do You Reduce Azure Compute Gallery Costs?

    Reduce Azure Compute Gallery storage costs by 60-90% through image version cleanup, replication right-sizing, and Citrix DaaS replica optimization.

    Spotto
    February 2026
    25 min read

    Azure Compute Gallery does not have its own line item on your invoice, which is exactly why gallery costs tend to drift. Every image replica in every target region is a managed disk charge buried in your storage bill, and cross-region replication adds egress on top. Organizations that replicate images to regions where no VMs consume them, or retain outdated image versions indefinitely, accumulate storage costs that scale with replica count, region count, and version count.

    Based on what we typically see, the two most effective optimizations are removing legacy image versions that no deployment references and right-sizing replica counts and target regions to match actual provisioning demand. Spotto's cloud optimization platform continuously identifies these overprovisioned gallery configurations and orphaned image versions, surfacing targeted recommendations that can reduce gallery storage costs by around 20-30% without impacting deployment performance.

    Key Takeaways at a Glance:

    Gallery costs hide in managed disk storage line items -- there is no separate Compute Gallery charge
    Remove image versions older than your retention window that have zero deployment references
    Right-size replica counts using the formula: ceil(concurrent_VMs / 20), minimum 3 for production
    Citrix DaaS default replica ratios are often more generous than needed -- tune them
    Combined optimizations can reduce gallery storage costs by around 60-90%

    What Problem This Solves

    Unchecked Image Sprawl Drives Silent Cost Growth

    Azure Compute Gallery has no standalone service fee. Every cost is an underlying managed disk charge per image replica per region. This indirect pricing model creates a blind spot.

    Two problems compound:

    Legacy version accumulation. Without lifecycle policies, galleries accumulate months or years of outdated versions. A gallery with 50 image definitions, 10 versions each, replicated to 5 regions = 2,500 managed disk replicas. At 128 GB per image, that's over 300 TB of billable storage.
    Over-replicated images. Azure recommends 1 replica per 20 concurrent VM deployments. Organizations that set high replica counts during initial rollout rarely revisit those settings.

    Business Impact:

    MSPs face multiplicative waste across customer galleries
    FinOps teams cannot attribute costs accurately
    DevOps teams experience slower image publishing
    Compliance teams face increased audit surface

    Financial example: Starting with 20 image definitions, 8 versions, 4 regions, 3 replicas = 1,920 total replicas. After optimization: 2 versions, 2 regions, demand-matched replicas = over 70% eliminated.

    Storage Tier Reference

    TierRedundancyUse CaseCost
    Standard_LRSLocal redundancyDev/test/archivalLowest cost
    Standard_ZRSZone redundancyProduction/HA~2x LRS
    Premium_LRSLocalHigh-IOPS workloads~2-3x Standard

    Notes: Default is Standard_LRS. ZRS is only available in regions with Availability Zones. Archive storage is NOT supported for VHD page blobs.

    How It Works

    Image Version Cleanup

    Legacy image versions accumulate because Azure Compute Gallery does not enforce retention policies natively. The end-of-life date property is informational only.

    Gallery Cost Growth Model:

    Gallery Cost Growth Model
    =========================
    
    Month 1:  5 definitions x 1 version  x 3 regions x 2 replicas =   30 managed disks
    Month 6:  5 definitions x 6 versions x 3 regions x 2 replicas =  180 managed disks
    Month 12: 5 definitions x 12 versions x 3 regions x 2 replicas = 360 managed disks
    Month 24: 5 definitions x 24 versions x 3 regions x 2 replicas = 720 managed disks
    
    At 128 GB per disk (Standard_LRS @ ~$5.89/mo per disk):
      Month 1:   $177/mo
      Month 6:   $1,060/mo
      Month 12:  $2,120/mo
      Month 24:  $4,240/mo
    
    Without cleanup, costs grow linearly with each new image version.

    Detection Logic -- 3 criteria:

    1. Age threshold (90-180 days)
    2. Deployment reference check (cross-reference against VMs, scale sets, AVD, CI/CD)
    3. Rollback requirement confirmation

    Decision Tree:

    Image Version Cleanup Decision Tree
    =====================================
    
    [Start] Is this the latest or second-latest version?
      |
      +-- YES --> RETAIN (rollback safety)
      |
      +-- NO  --> Is it older than the retention window (90-180 days)?
            |
            +-- NO  --> RETAIN (within retention window)
            |
            +-- YES --> Does any active VM/VMSS/AVD/pipeline reference this version?
                  |
                  +-- YES --> RETAIN but right-size target regions
                  |
                  +-- NO  --> Is there a compliance hold on this version?
                        |
                        +-- YES --> ARCHIVE to Standard_LRS in a single region
                        |
                        +-- NO  --> DELETE

    Implementation -- Inventory CLI commands:

    # List all galleries in the subscription
    az sig list --query "[].{Name:name, ResourceGroup:resourceGroup, Location:location}" -o table
    
    # List all image definitions in a gallery
    az sig image-definition list \
      --gallery-name <gallery-name> \
      --resource-group <rg-name> \
      --query "[].{Name:name, OsType:osType, Publisher:identifier.publisher}" -o table
    
    # List all image versions for a definition with age and replication details
    az sig image-version list \
      --gallery-name <gallery-name> \
      --gallery-image-definition <definition-name> \
      --resource-group <rg-name> \
      --query "[].{Version:name, Created:publishingProfile.publishedDate, \
        EOL:publishingProfile.endOfLifeDate, \
        Regions:publishingProfile.targetRegions[].name, \
        ReplicaCount:publishingProfile.targetRegions[].regionalReplicaCount, \
        StorageType:publishingProfile.storageAccountType}" -o table
    
    # Count total replicas across all galleries
    az sig list --query "[].name" -o tsv | while read gallery; do
      rg=$(az sig show --gallery-name "$gallery" --query "resourceGroup" -o tsv)
      az sig image-definition list --gallery-name "$gallery" --resource-group "$rg" \
        --query "[].name" -o tsv | while read def; do
        az sig image-version list --gallery-name "$gallery" \
          --gallery-image-definition "$def" --resource-group "$rg" \
          --query "[].publishingProfile.targetRegions[].regionalReplicaCount" -o tsv
      done
    done | paste -sd+ | bc

    Cleanup PowerShell Runbook:

    # Azure Automation Runbook: Gallery Image Version Cleanup
    # Schedule: Weekly, during maintenance window
    
    param(
        [string]$GalleryName,
        [string]$ResourceGroupName,
        [int]$RetentionDays = 180,
        [int]$KeepLatestVersions = 2,
        [bool]$DryRun = $true
    )
    
    Connect-AzAccount -Identity
    
    $definitions = Get-AzGalleryImageDefinition -GalleryName $GalleryName \
        -ResourceGroupName $ResourceGroupName
    
    foreach ($def in $definitions) {
        $versions = Get-AzGalleryImageVersion -GalleryName $GalleryName \
            -ResourceGroupName $ResourceGroupName \
            -GalleryImageDefinitionName $def.Name |
            Sort-Object -Property Name -Descending
    
        # Always keep the latest N versions
        $candidates = $versions | Select-Object -Skip $KeepLatestVersions
    
        foreach ($ver in $candidates) {
            $age = (Get-Date) - $ver.PublishingProfile.PublishedDate
            if ($age.TotalDays -gt $RetentionDays) {
                # Check for active VM references
                $refCount = (az graph query -q "Resources \
                    | where type =~ 'microsoft.compute/virtualmachines' \
                    | where properties.storageProfile.imageReference.id \
                        contains '$($ver.Id)'" --query "count_" -o tsv)
    
                if ([int]$refCount -eq 0) {
                    if ($DryRun) {
                        Write-Output "[DRY RUN] Would delete: $($def.Name) v$($ver.Name) \
                            (age: $([math]::Round($age.TotalDays)) days, refs: 0)"
                    } else {
                        Remove-AzGalleryImageVersion -GalleryName $GalleryName \
                            -ResourceGroupName $ResourceGroupName \
                            -GalleryImageDefinitionName $def.Name \
                            -Name $ver.Name -Force
                        Write-Output "Deleted: $($def.Name) v$($ver.Name)"
                    }
                } else {
                    Write-Output "Skipped: $($def.Name) v$($ver.Name) \
                        (active refs: $refCount)"
                }
            }
        }
    }

    Failure mode warning: Always run the cleanup with $DryRun = $true first. Deleting an image version that is actively referenced by a VM scale set will not break running VMs, but it will prevent new instances from being provisioned from that version. Verify all references before deleting.

    Replication Right-Sizing

    The Over-Replication Pattern:

    Over-Replication Example
    ========================
    
    Configured:  5 regions x 8 replicas = 40 disks per version
    Actual:      2 regions actively deploying, max 30 concurrent VMs
    Required:    2 regions x 3 replicas  = 6 disks per version
    Waste:       34 unnecessary disks (85%)
    
    At 128 GB Standard_LRS (~$5.89/disk/mo):
      Configured cost:  $236/mo per version
      Required cost:    $35/mo per version
      Savings:          $201/mo per version
    
    With 10 active versions: $2,010/mo in unnecessary storage

    Detection Logic:

    1. Region utilization -- Compare target regions against regions where VMs are actually deployed
    2. Replica count vs concurrent deployments -- Azure recommends 1 replica per 20 concurrent VM deployments
    3. Storage tier alignment -- Ensure the storage tier matches the workload requirements

    Replica Sizing Flow:

    Replica Sizing Decision Flow
    =============================
    
    [Start] For each target region:
      |
      +-- Any VM/VMSS/AVD deployments in this region?
            |
            +-- NO  --> Is this a DR-only region?
            |     |
            |     +-- YES --> Keep 1 replica, Standard_LRS
            |     +-- NO  --> REMOVE region from target list
            |
            +-- YES --> Calculate required replicas:
                  |
                  +-- VM-based: ceil(concurrent_VMs / 20)
                  +-- VMSS-based: concurrent_scale_sets + 1
                  |
                  +-- Is this a production workload?
                        |
                        +-- YES --> max(calculated, 3) + 1-2 buffer replicas
                        +-- NO  --> max(calculated, 1) (dev/test)

    Right-sizing implementation:

    # Update replica count for an image version
    az sig image-version update \
      --gallery-name <gallery-name> \
      --gallery-image-definition <definition-name> \
      --gallery-image-version <version> \
      --resource-group <rg-name> \
      --target-regions <region1>=<replica-count>=<storage-type> \
                       <region2>=<replica-count>=<storage-type>
    
    # Example: Reduce from 5 regions/8 replicas to 2 regions/3 replicas
    az sig image-version update \
      --gallery-name gallery-prod \
      --gallery-image-definition win11-enterprise \
      --gallery-image-version 1.0.0 \
      --resource-group rg-images \
      --target-regions eastus=3=Standard_LRS westus2=3=Standard_LRS
    
    # Remove a region entirely by omitting it from --target-regions
    # (the image version must retain at least one target region)

    Important: Reducing replica counts below the concurrent deployment demand will cause provisioning throttling. Always validate concurrent VM creation rates in each region before reducing replicas. The 1:20 ratio (1 replica per 20 concurrent VMs) is a minimum guideline, not a hard limit.

    Citrix DaaS Considerations

    Citrix DaaS (formerly Virtual Apps and Desktops service) uses Azure Compute Gallery for machine catalog images and applies its own replica settings on top of Azure defaults.

    Default Citrix Replica Settings:

    Catalog TypeDefault Ratio (VMs per Replica)Max Replicas
    Non-Persistent40100
    Persistent1000100

    Key optimization: For 200 non-persistent machines with the default ratio of 40, Citrix creates 5 replicas (200 / 40 = 5). If the actual concurrent demand is only 60 machines, setting the ratio to 60 reduces the replica count to 4. For larger catalogs, the savings scale proportionally.

    Adjusting Citrix DaaS replica ratio:

    # Adjust Citrix DaaS machine catalog replica ratio
    # Run from Citrix Cloud PowerShell or Remote PowerShell SDK
    
    # View current provisioning scheme settings
    Get-ProvScheme -ProvisioningSchemeName "MyCatalog" |
        Select-Object ProvisioningSchemeName,
        MachineCount,
        UseSharedImageGallery,
        SharedImageGalleryReplicaRatio,
        SharedImageGalleryReplicaMaximum
    
    # Update the replica ratio from default 40 to 60
    Set-ProvScheme -ProvisioningSchemeName "MyCatalog" \
        -CustomProperties @"
    <CustomProperties xmlns="http://schemas.citrix.com/2014/xd/machinecreation">
        <Property xsi:type="StringProperty" Name="SharedImageGalleryReplicaRatio" Value="60" />
        <Property xsi:type="StringProperty" Name="SharedImageGalleryReplicaMaximum" Value="10" />
    </CustomProperties>
    "@
    
    # Verify the change
    Get-ProvScheme -ProvisioningSchemeName "MyCatalog" |
        Select-Object SharedImageGalleryReplicaRatio, SharedImageGalleryReplicaMaximum

    Failure mode warning: Setting the replica ratio too high (too few replicas) will cause Citrix provisioning failures during burst periods when many machines power on simultaneously. Monitor Citrix Cloud provisioning logs for throttling errors after adjusting the ratio. Start conservatively and reduce gradually.

    Common Questions

    1. Why does Azure Compute Gallery not appear on my invoice?

    Azure Compute Gallery itself is a free orchestration layer. The costs come from the underlying managed disks that store each image replica. These charges appear under "Managed Disks" or "Storage" in your invoice, not as a separate gallery line item. This makes gallery costs difficult to identify without cross-referencing disk resources against gallery image versions.

    2. How do I calculate my current gallery storage cost?

    Total cost = (number of image definitions) x (versions per definition) x (target regions) x (replicas per region) x (managed disk cost for the image size and storage tier). Use the inventory CLI commands above to count your total replicas, then multiply by the per-disk cost for your image size and storage tier.

    3. Is it safe to delete old image versions?

    Yes, provided no running VM, scale set, AVD host pool, or CI/CD pipeline references that version. Deleting an unreferenced version has no impact on running workloads. However, deleting a version that is still referenced will not break running VMs -- it will only prevent new VMs from being provisioned from that specific version.

    4. What is the recommended retention policy?

    Most organizations retain the latest 2 versions and set a retention window of 90-180 days for older versions. The latest 2 versions provide rollback capability. Anything beyond the retention window that has no active deployment references is a deletion candidate. Compliance requirements may extend this window.

    5. How many replicas do I actually need?

    Azure recommends 1 replica per 20 concurrent VM deployments. For production workloads, use a minimum of 3 replicas plus 1-2 buffer replicas. For dev/test, 1 replica is usually sufficient. The formula is: ceil(concurrent_VMs / 20) for VMs, or concurrent_scale_sets + 1 for VMSS.

    6. What happens if I reduce replicas too aggressively?

    If the replica count drops below the concurrent deployment demand, Azure will throttle VM provisioning requests. This manifests as slower scale-out times and potential provisioning failures during burst periods. The impact is most visible in auto-scaling scenarios and Citrix DaaS power management.

    7. Should I use Standard_LRS or Standard_ZRS?

    Use Standard_ZRS for production images in regions with Availability Zones where you need zone-resilient deployments. Use Standard_LRS for dev/test, archival, and DR-only regions. ZRS costs approximately 2x LRS, so downgrading non-critical replicas from ZRS to LRS provides immediate savings.

    8. How does this interact with Citrix DaaS machine catalogs?

    Citrix DaaS manages its own replica settings through the provisioning scheme. The default ratio of 40 VMs per replica for non-persistent catalogs is often more generous than needed. You can adjust the ratio using Set-ProvScheme to match your actual concurrent boot demand. Changes take effect on the next image update cycle.

    9. Can I automate gallery cleanup?

    Yes. Deploy the PowerShell runbook provided above as an Azure Automation runbook on a weekly schedule. Start with DryRun = $true to validate the cleanup candidates, then switch to $false for automated deletion. Pair this with Azure Policy to enforce tagging on gallery resources for better tracking.

    10. What about cross-region replication egress costs?

    Every time you replicate an image version to a new region, Azure charges egress for the data transfer. Removing unused target regions eliminates both the ongoing managed disk storage cost and the one-time egress cost for future image versions. This is a double saving.

    11. How does Spotto help with gallery cost optimization?

    Spotto continuously monitors your Azure Compute Gallery configurations, identifies orphaned image versions, detects over-replicated images, and surfaces right-sizing recommendations. Rather than running one-off audits, Spotto provides ongoing visibility and alerts when gallery configurations drift from optimal -- especially valuable for MSPs managing multiple customer galleries.

    12. Can I apply these optimizations across multiple tenants?

    Yes. MSPs can script the inventory and cleanup across all tenants using Azure Lighthouse or by iterating over subscriptions. The cleanup runbook supports parameterized gallery names and resource groups, making it straightforward to deploy across multiple environments. Spotto automates this cross-tenant visibility natively.

    Use-Case and Scenario Coverage

    Scenario 1: MSP Managing 15 Customer Galleries

    Before

    $18,000/mo

    15 galleries, avg 12 versions, 4 regions, 5 replicas

    After

    $3,600/mo

    2 versions retained, 2 regions, demand-matched replicas

    Actions taken: Removed 10 legacy versions per gallery. Eliminated 2 unused target regions. Right-sized replica counts from 5 to 2-3 based on actual concurrent deployments. Downgraded dev/test replicas from ZRS to LRS.

    80% savings -- $172,800/year

    Scenario 2: Enterprise Citrix DaaS Deployment

    Before

    $8,500/mo

    500 non-persistent VDAs, default ratio 40, 13 replicas

    After

    $3,400/mo

    Ratio adjusted to 80, 7 replicas, old versions cleaned

    Actions taken: Analyzed actual concurrent boot demand (peak 350 VDAs). Adjusted Citrix replica ratio from 40 to 80. Reduced replicas from 13 to 7. Cleaned 6 obsolete image versions. Moved archival versions to Standard_LRS single-region.

    60% savings -- $61,200/year

    Scenario 3: DevOps Team with CI/CD Image Pipeline

    Before

    $4,200/mo

    Weekly image builds, 52 versions/year, no cleanup

    After

    $420/mo

    Automated cleanup to 4 versions, 1 region for dev

    Actions taken: Implemented automated cleanup runbook in CI/CD pipeline. Retained only latest 4 versions (1 month of weekly builds). Reduced dev/test gallery to single region with 1 replica. Production gallery kept at 2 regions with 3 replicas.

    90% savings -- $45,360/year

    Scenario 4: AVD Host Pool Image Management

    Before

    $6,800/mo

    3 host pools, 8 versions each, ZRS in 3 regions

    After

    $1,700/mo

    2 versions, ZRS in primary region, LRS in DR

    Actions taken: Reduced retention to 2 versions per host pool image definition. Kept ZRS only in the primary deployment region. Switched DR region to Standard_LRS with 1 replica. Removed the third region where no AVD sessions were hosted.

    75% savings -- $61,200/year

    Implementation Guidance

    Preconditions

    Azure CLI or PowerShell Az module installed and authenticated
    Contributor role on resource groups containing galleries (or Compute Gallery Contributor)
    Azure Resource Graph access for cross-subscription queries
    Change management approval for production gallery modifications
    For Citrix environments: Citrix Cloud PowerShell SDK or Remote PowerShell access

    Required Inputs

    Subscription IDs for all Azure subscriptions containing galleries
    Gallery names and resource groups
    Current VM/VMSS/AVD deployment regions and concurrent provisioning rates
    Citrix provisioning scheme names (for Citrix DaaS environments)
    Compliance and retention requirements for image version lifecycle

    Rollout Approach

    Step 1: Discovery -- Run the inventory CLI commands to catalog all galleries, image definitions, versions, target regions, and replica counts across all subscriptions. Export the results for analysis.
    Step 2: Dependency mapping -- Cross-reference image versions against running VMs, scale sets, AVD host pools, and CI/CD pipelines using Azure Resource Graph. Tag each version as "active," "rollback," or "orphaned."
    Step 3: Dry run -- Execute the cleanup runbook with DryRun = $true. Review the list of versions that would be deleted. Validate that no active references are missed.
    Step 4: Phased cleanup -- Start with dev/test galleries. Delete orphaned versions and reduce replicas. Monitor for 1 week to confirm no provisioning issues.
    Step 5: Production cleanup -- Apply the same cleanup to production galleries during a maintenance window. Retain the latest 2 versions and remove orphaned versions beyond the retention window.
    Step 6: Replication right-sizing -- Adjust target regions and replica counts based on actual deployment patterns. Remove unused regions. Right-size replicas using the formula.
    Step 7: Automation deployment -- Deploy the cleanup runbook as an Azure Automation scheduled task. Set up Spotto monitoring for ongoing drift detection.

    Failure Modes

    Provisioning failures after version deletion: If a deleted image version is still referenced by a scale set or AVD host pool, new VM provisioning will fail. Always verify references with Azure Resource Graph before deleting.
    Throttling after replica reduction: Reducing replicas below concurrent deployment demand causes provisioning throttling. Monitor scale-out times for 48 hours after any replica count change.
    Citrix burst failures: Adjusting the Citrix replica ratio too aggressively can cause failures during morning logon storms when many VDAs power on simultaneously. Start with a conservative ratio adjustment and monitor.
    DR region removal: Removing a target region that serves as a disaster recovery site will prevent VM deployment in that region during a failover event. Always confirm DR requirements before removing regions.

    Rollback Strategy

    Every optimization should have a clear rollback path:

    Version deletion rollback: Deleted image versions cannot be recovered. Before deleting, ensure you can rebuild the image from source (Packer template, VM capture, etc.). Keep the image build pipeline artifacts for at least 90 days beyond the gallery retention window.
    Replica count rollback: Increase the replica count back to the previous value using az sig image-version update. Replication to the target region takes time proportional to image size. Allow 30-60 minutes for a 128 GB image.
    Region removal rollback: Re-add the region as a target by updating the image version's target regions. The image will be replicated to the region, which incurs egress costs and takes time.
    Citrix ratio rollback: Revert the Set-ProvScheme replica ratio to the previous value. The change takes effect on the next image update or catalog update cycle.

    Cost Impact Summary

    RecommendationTypical SavingsComplexity
    Remove legacy image versions20-30%Low
    Remove unused target regions15-40%Low
    Right-size replica counts10-25%Medium
    Downgrade ZRS to LRS (non-critical)~50% per replicaLow
    Citrix DaaS replica ratio optimization30-60%Low
    Combined optimizations60-90%Medium

    What to Do Next

    Step 1: Run the inventory -- Use the CLI commands above to catalog every gallery, image definition, version, and replica across your subscriptions. Export to a spreadsheet for analysis.
    Step 2: Identify quick wins -- Look for image versions older than 180 days with no active references. These are safe to delete immediately and often represent the largest cost reduction.
    Step 3: Right-size replicas and regions -- Compare your target regions against actual deployment locations. Remove unused regions and adjust replica counts to match the concurrent deployment formula.
    Step 4: Automate -- Deploy the cleanup runbook on a recurring schedule and set up monitoring to prevent future drift. Consider Spotto for continuous, automated gallery optimization across all your environments.

    Summary

    Gallery costs are hidden -- Every image replica is a managed disk charge buried in your storage bill. There is no separate Compute Gallery line item, making cost attribution difficult without deliberate analysis.
    Version cleanup delivers immediate savings -- Most galleries accumulate months or years of unused image versions. Removing versions beyond your retention window that have no deployment references is the lowest-risk, highest-impact optimization.
    Replication right-sizing compounds the savings -- Reducing replica counts and removing unused target regions addresses the multiplicative cost structure of galleries. Use ceil(concurrent_VMs / 20) as your baseline.
    Citrix DaaS defaults are generous -- The default replica ratio of 40 VMs per replica often creates more replicas than concurrent boot demand requires. Tuning the ratio is a low-risk optimization with measurable savings.
    Storage tier selection matters -- Downgrading non-critical replicas from ZRS to LRS halves the per-replica cost. Reserve ZRS for production images in your primary deployment region.
    Automation prevents drift -- One-off cleanups help, but without automated retention and monitoring, gallery costs will regrow. Deploy scheduled cleanup runbooks and continuous monitoring to maintain savings.

    The challenges outlined in this article — image version sprawl, over-replicated galleries, hidden managed disk charges — are the same ones our customers work through across their Azure environments. The difference is they use Spotto to surface these opportunities automatically, rather than running the analysis by hand.

    Stop Paying for Images Nobody Deploys

    Spotto continuously analyzes your Azure Compute Gallery configurations to detect orphaned image versions, over-replicated galleries, and storage tier mismatches — giving you clear, actionable recommendations to eliminate gallery waste across every subscription.

    Free Trial

    Disclaimer: This article is provided for informational purposes only and does not constitute professional advice. Azure pricing, features, and service behavior may have changed since publication. Always validate recommendations against your specific environment and consult Microsoft's official documentation before making changes to production infrastructure. Spotto is not liable for any actions taken based on the content of this article.