How to Configure Storage Tiering with Storage Spaces on Windows Server 2025

Storage tiering is one of the most powerful features of Windows Server Storage Spaces, allowing you to combine fast SSD storage and high-capacity HDD storage into a single logical volume that automatically places frequently accessed (hot) data on the SSD tier and cold data on the HDD tier. Windows Server 2025 enhances this capability with improved tiering algorithms, better integration with Storage Spaces Direct (S2D), and refined PowerShell tooling for monitoring and management. The result is a cost-effective storage solution that delivers near-SSD performance for active workloads while maintaining the economics of spinning disk for bulk data — all managed transparently by the operating system. This tutorial walks through creating a tiered storage pool from mixed physical disks, creating a tiered virtual disk, pinning specific folders to the SSD tier, monitoring tier health and utilization, understanding the scheduled optimization job, and reviewing how S2D extends the tiering concept with its NVMe/SSD cache tier.

Prerequisites

  • Windows Server 2025 Standard or Datacenter edition
  • At least two SSD physical disks and at least two HDD physical disks that are not currently part of any pool or volume (raw, uninitialized disks work best)
  • Disks must be visible in Get-PhysicalDisk with CanPool -eq $true
  • For S2D: All disks on all cluster nodes must be directly attached (no shared SAS enclosures) and the cluster must have S2D enabled
  • Administrator credentials on the server
  • PowerShell 5.1 or later running as Administrator
  • The Storage module is built-in — no additional installation is needed

Step 1 — Identify Available Physical Disks

Before creating a pool, inventory the physical disks available on the server. Storage Spaces needs to know which disks are SSDs and which are HDDs — this information is read from the disk’s media type attribute.

# List all disks and their pool eligibility
Get-PhysicalDisk | Select-Object FriendlyName, MediaType, Size, CanPool, HealthStatus |
    Format-Table -AutoSize

# Filter to only poolable disks
Get-PhysicalDisk | Where-Object CanPool -eq $true |
    Select-Object FriendlyName, MediaType, Size, UniqueId | Format-Table -AutoSize

# If MediaType shows "Unspecified" for a disk you know is SSD, set it manually
Set-PhysicalDisk -FriendlyName "PhysicalDisk3" -MediaType SSD
Set-PhysicalDisk -FriendlyName "PhysicalDisk4" -MediaType HDD

Accurate media type assignment is critical — Storage Spaces uses it to determine which physical disks belong to the SSD tier and which belong to the HDD tier. NVMe drives typically identify correctly as SSD. Some enterprise SAS SSDs may report as Unspecified and need to be corrected with Set-PhysicalDisk.

Step 2 — Create a Tiered Storage Pool

A storage pool is a collection of physical disks managed as a single unit. Create one pool containing all your SSDs and HDDs together. Storage Spaces will internally track which physical disks are SSD and which are HDD for tier assignment.

# Collect the poolable physical disks
$poolDisks = Get-PhysicalDisk | Where-Object CanPool -eq $true

# Create the storage pool
New-StoragePool `
    -FriendlyName "TieredPool01" `
    -StorageSubSystemFriendlyName "Windows Storage*" `
    -PhysicalDisks $poolDisks

# Verify the pool was created
Get-StoragePool -FriendlyName "TieredPool01" |
    Select-Object FriendlyName, HealthStatus, OperationalStatus, Size, AllocatedSize

# Review which disks are in the pool and their media types
Get-StoragePool -FriendlyName "TieredPool01" |
    Get-PhysicalDisk |
    Select-Object FriendlyName, MediaType, Size, HealthStatus | Format-Table -AutoSize

By default, the pool reserves some space on each physical disk for hot spare capacity. You can configure the number of hot spares or use manual allocation depending on your redundancy strategy. For tiered volumes, both the SSD and HDD portions can use mirror or parity resiliency independently.

Step 3 — Create Storage Tiers Within the Pool

Before creating a tiered virtual disk, define the storage tiers explicitly within the pool. This tells Storage Spaces how to group the SSD and HDD disks for tier-aware virtual disk creation.

# Create the SSD tier within the pool
New-StorageTier `
    -StoragePoolFriendlyName "TieredPool01" `
    -FriendlyName "SSDTier" `
    -MediaType SSD `
    -ResiliencySettingName Mirror

# Create the HDD tier within the pool
New-StorageTier `
    -StoragePoolFriendlyName "TieredPool01" `
    -FriendlyName "HDDTier" `
    -MediaType HDD `
    -ResiliencySettingName Mirror

# Verify the tiers were created
Get-StorageTier | Select-Object FriendlyName, MediaType, ResiliencySettingName,
    Size, AllocatedSize | Format-Table -AutoSize

# Check supported sizes for each tier to plan your allocation
Get-StorageTierSupportedSize -StoragePoolFriendlyName "TieredPool01" -FriendlyName "SSDTier" |
    Select-Object TierSizeMin, TierSizeMax, TierSizeDivisor

Get-StorageTierSupportedSize -StoragePoolFriendlyName "TieredPool01" -FriendlyName "HDDTier" |
    Select-Object TierSizeMin, TierSizeMax, TierSizeDivisor

Using Mirror resiliency for both tiers is recommended for workloads where performance and protection are both priorities. You can also use Parity for the HDD tier to maximize capacity efficiency at the cost of write performance — this is appropriate for archival data that is read-intensive. The SSD tier should almost always use Mirror for low-latency write performance.

Step 4 — Create the Tiered Virtual Disk

With the tiers defined, create a virtual disk that spans both tiers. You specify the size allocated to each tier independently, giving you precise control over the SSD/HDD split.

# Retrieve the tier objects
$ssdTier = Get-StorageTier -FriendlyName "SSDTier"
$hddTier = Get-StorageTier -FriendlyName "HDDTier"

# Create a tiered virtual disk: 200GB SSD tier + 2TB HDD tier
New-VirtualDisk `
    -StoragePoolFriendlyName "TieredPool01" `
    -FriendlyName "TieredVolume01" `
    -StorageTiers @($ssdTier, $hddTier) `
    -StorageTierSizes @(200GB, 2TB) `
    -WriteCacheSize 1GB

# Verify the virtual disk
Get-VirtualDisk -FriendlyName "TieredVolume01" |
    Select-Object FriendlyName, HealthStatus, OperationalStatus,
                  Size, FootprintOnPool, WriteCacheSize

# Initialize, partition, and format the virtual disk
$disk = Get-VirtualDisk -FriendlyName "TieredVolume01" | Get-Disk
Initialize-Disk -Number $disk.Number -PartitionStyle GPT
New-Partition -DiskNumber $disk.Number -UseMaximumSize -DriveLetter T
Format-Volume -DriveLetter T -FileSystem NTFS -NewFileSystemLabel "TieredVolume" -Confirm:$false

The -WriteCacheSize 1GB parameter enables the write-back cache on the SSD tier. This cache absorbs write I/O bursts before they are committed to either tier, significantly improving write latency for mixed workloads. The write cache is separate from the tier allocation and is carved from SSD capacity automatically.

Step 5 — Pin Specific Folders to the SSD Tier

By default, the tiering optimizer moves data between tiers based on access frequency. However, you can pin specific files or folders permanently to the SSD tier using Set-FileStorageTier. This is useful for database transaction logs, virtual machine configuration files, or any data that must always have sub-millisecond access times regardless of access frequency.

# Create a directory structure on the tiered volume
New-Item -Path "T:HotData" -ItemType Directory
New-Item -Path "T:ColdData" -ItemType Directory

# Pin the HotData folder to the SSD tier
Set-FileStorageTier `
    -FilePath "T:HotData" `
    -DesiredStorageTier (Get-StorageTier -FriendlyName "SSDTier")

# Verify the pinning assignment
Get-FileStorageTier -VolumePath "T:" |
    Select-Object FilePath, DesiredStorageTierFriendlyName, CurrentStorageTierFriendlyName

# Pin an individual file (e.g., a database file) to the SSD tier
Set-FileStorageTier `
    -FilePath "T:ColdDatacritical-index.mdf" `
    -DesiredStorageTier (Get-StorageTier -FriendlyName "SSDTier")

The CurrentStorageTierFriendlyName shows where the data physically resides now, while DesiredStorageTierFriendlyName shows where the tiering optimizer will move it during the next optimization pass. If these values differ, the data will be relocated during the next scheduled optimization run.

Step 6 — Monitor Tier Health and Utilization

Regular monitoring of tier health and space utilization prevents SSD tier exhaustion — a condition where the SSD tier is full and hot data cannot be promoted, degrading performance to HDD speeds.

# View tier health and allocation
Get-StorageTier | Select-Object FriendlyName, HealthStatus, OperationalStatus,
    @{Name="SizeGB"; Expression={[math]::Round($_.Size/1GB,2)}},
    @{Name="AllocatedGB"; Expression={[math]::Round($_.AllocatedSize/1GB,2)}},
    @{Name="UsedPct"; Expression={[math]::Round(($_.AllocatedSize/$_.Size)*100,1)}} |
    Format-Table -AutoSize

# Check the health of the underlying physical disks in the pool
Get-StoragePool -FriendlyName "TieredPool01" | Get-PhysicalDisk |
    Select-Object FriendlyName, MediaType, HealthStatus, OperationalStatus,
                  @{Name="SizeGB"; Expression={[math]::Round($_.Size/1GB,2)}} |
    Format-Table -AutoSize

# View the virtual disk health summary
Get-VirtualDisk -FriendlyName "TieredVolume01" |
    Select-Object FriendlyName, HealthStatus, OperationalStatus,
                  DetachedReason, WriteCacheSize

# Check NTFS volume health
Get-Volume -DriveLetter T |
    Select-Object DriveLetter, FileSystemLabel, HealthStatus, SizeRemaining, Size

Set up a scheduled monitoring task that alerts when SSD tier utilization exceeds 80 percent. At that threshold, consider expanding the SSD tier by adding more SSD physical disks to the pool, or review whether some pinned files can be moved to the HDD tier.

Step 7 — Run and Schedule Tiering Optimization

Windows Server automatically schedules a storage optimizer task that runs weekly by default. This task analyzes I/O heat patterns and moves data between tiers accordingly. You can trigger it manually with Optimize-StoragePool and inspect the scheduled task configuration.

# Manually trigger a tiering optimization pass
Optimize-StoragePool -FriendlyName "TieredPool01"

# Or trigger optimization at the volume level via the defragmentation engine
Optimize-Volume -DriveLetter T -TierOptimize -Verbose

# View the scheduled optimization task
Get-ScheduledTask | Where-Object TaskName -like "*StorageTier*" |
    Select-Object TaskName, State, LastRunTime, NextRunTime

# Modify the schedule to run daily at 2AM instead of weekly
$trigger = New-ScheduledTaskTrigger -Daily -At 2:00AM
Set-ScheduledTask `
    -TaskName "Storage Tiers Optimization" `
    -TaskPath "MicrosoftWindowsStorage Tiers Management" `
    -Trigger $trigger

The -TierOptimize switch in Optimize-Volume specifically triggers the inter-tier data movement pass, as opposed to -Defrag which consolidates free space within a tier. For tiered volumes, Microsoft recommends running both passes periodically: -TierOptimize weekly and -Defrag monthly. Note that the HDD tier benefits from defragmentation while the SSD tier does not (and should not be defragmented).

Step 8 — Storage Spaces Direct Cache Tier Overview

In Storage Spaces Direct (S2D) deployments on Windows Server 2025, the tiering architecture extends to a dedicated cache layer separate from the capacity tiers. S2D automatically uses the fastest devices (NVMe or SSD) as a write-back read/write cache for the slower capacity devices (SSD or HDD), delivering exceptional performance without any manual tier configuration.

# On an S2D cluster — view the cache and capacity tiers
Get-StorageTier | Select-Object FriendlyName, MediaType, Usage,
    @{Name="SizeGB"; Expression={[math]::Round($_.Size/1GB,2)}}

# View the S2D cache configuration
Get-StorageHealthReport -CimSession ClusterNode01 |
    Select-Object -ExpandProperty Faults

# Check S2D cache drive assignments
Get-PhysicalDisk | Where-Object Usage -eq Journal |
    Select-Object FriendlyName, MediaType, Size, HealthStatus

# View per-disk cache statistics (requires Storage Health service)
Get-StorageHealthReport | Select-Object -ExpandProperty Faults |
    Where-Object FaultType -like "*Cache*"

In S2D, NVMe drives used as cache devices are labeled with Usage = Journal. Each cache device is bound to a set of capacity devices on the same server, and the binding is managed automatically by S2D. Unlike traditional tiering where data permanently lives on one tier, S2D cache operates as a true write-back buffer — recently written and frequently read data lives in cache, and less active data flows to the capacity tier through background de-staging. This architecture eliminates the need to manually pin files or schedule optimization passes in most S2D deployments.

Conclusion

Storage tiering with Storage Spaces on Windows Server 2025 gives you a practical path to high-performance storage without the cost of an all-flash array. By building a tiered pool from mixed SSD and HDD disks, defining explicit tier objects, creating tiered virtual disks with precise SSD-to-HDD capacity ratios, pinning latency-sensitive data permanently to the SSD tier, and scheduling regular optimization passes, you can deliver a storage experience that adapts to your workload’s changing hot-data patterns automatically. The monitoring cmdlets ensure you catch SSD tier exhaustion before it impacts performance, and the S2D cache tier model shows how Microsoft has taken these principles even further in hyperconverged deployments. Whether you are managing a standalone server or a multi-node S2D cluster, the PowerShell storage stack in Windows Server 2025 gives you full visibility and control over every layer of your tiered storage architecture.