Most administrators meet fsutil exactly once, in a forum answer that says to run fsutil hardlink list or fsutil dirty query, and never look at the rest of it. That is a shame, because fsutil is the only built in tool that talks to NTFS at the level NTFS actually works: clusters, allocation ranges, valid data length, the MFT zone.
The practical payoff is narrow but real. It creates a file of an exact size in under a second instead of copying data for twenty minutes. It explains why a 40 GB file occupies 200 MB on disk, and why your backup software disagrees with Explorer about how big that file is. It reports free space the way the file system sees it, not the way a quota rounds it.
The Microsoft reference lists eighteen subcommands with their syntax and almost no output. This page takes the ones that earn their place in a normal working day, shows what each prints, and flags the two spots where fsutil will quietly do something you did not intend.
Applies to: Windows 10 / 11, Windows Server 2016 / 2019 / 2022
Quick answer
Open an elevated Command Prompt. Every fsutil subcommand below requires membership in the local Administrators group, and most of them fail with a flat access denied message rather than a useful one if you forget.
rem Create the working folder used by every example on this page
md C:\bat\test
rem A 1 GB file, created instantly, for testing a backup job or a low-space alert
fsutil file createnew C:\bat\test\bigfile.dat 1073741824
rem What the file system says is left on the volume, in bytes
fsutil volume diskfree C:
rem Is this file sparse? Answers the "size on disk does not match size" question
fsutil sparse queryflag C:\bat\test\bigfile.dat
The last three commands are read only. The first one writes a real 1 GB file, so run it somewhere with room. Everything created on this page is removed in the cleanup step at the end of the examples.
What fsutil does
fsutil is a front end for file system control codes. It does not have its own logic to speak of: each subcommand maps onto an FSCTL that NTFS already implements, which is why the tool can do things Explorer and PowerShell cannot, and why it offers no confirmation prompts when it does them.
The grammar is fsutil SUBCOMMAND PARAMETER arguments. Running a subcommand with no parameter prints its own usage, which is the fastest syntax check on a machine you are already logged into.
| Subcommand | What it covers | Used on this page |
|---|---|---|
fsutil file | Create files of an exact size, query and set allocation ranges, valid data length, file IDs and short names | Yes |
fsutil volume | Free space, volume list, cluster to file lookup, dismount | Yes |
fsutil sparse | Set and query the sparse attribute, list allocated ranges, mark ranges sparse | Yes |
fsutil fsinfo | Drive list, drive type, volume and NTFS geometry, sector size, file system statistics | Yes |
fsutil behavior | Volume wide NTFS tuning: last access updates, 8.3 name creation, MFT zone, delete notify | Yes |
fsutil usn | The update sequence number change journal: create, query, read, delete | Hidden gems |
fsutil hardlink | Create and list NTFS hard links | See the NTFS links guide |
fsutil reparsepoint | Query and delete reparse points behind junctions and symlinks | See the NTFS links guide |
fsutil dirty | Query and set the volume dirty bit that triggers autochk at boot | See the chkntfs guide |
fsutil 8dot3name | Query, set, scan for and strip 8.3 short names. strip /t is a test mode that reports what would be removed and changes nothing | No |
fsutil quota, repair, objectid | Disk quotas, NTFS self healing state, object identifiers | No |
fsutil resource, transaction, tiering, devdrv, wim, clfs | Transactional NTFS, storage tiers, Dev Drive, WIM backed files, CLFS | No |
fsutil devdrv and fsutil wim are recent additions. If a subcommand in the table is missing on your build, run fsutil with no arguments to see what that machine actually supports.
Practical examples
All six examples use the same folder, C:\bat\test, and build on each other. Create it first if you have not already, and run everything from an elevated prompt.
md C:\bat\test
cd /d C:\bat\test
1. Create a file of an exact size, instantly
The problem: you need a 1 GB file to test whether a backup job handles large files, or to push a volume close to its low space threshold and confirm the monitoring alert fires. Copying real data takes minutes and gives a size you did not choose.
The solution: fsutil file createnew allocates the requested number of bytes and returns immediately, because NTFS records the size without writing a byte of it. The length is in decimal bytes, with no MB or GB suffix anywhere in fsutil.
rem Length is in bytes: 1024 * 1024 * 1024 = 1073741824
fsutil file createnew C:\bat\test\bigfile.dat 1073741824
rem Confirm the size NTFS recorded
dir C:\bat\test\bigfile.dat
fsutil confirms the creation on one line, and dir reports the full size straight away:
File C:\bat\test\bigfile.dat is created
Volume in drive C has no label.
Directory of C:\bat\test
07/09/2026 09:14 1,073,741,824 bigfile.dat
1 File(s) 1,073,741,824 bytes
2. Read the free space the file system actually sees
The problem: a monitoring agent says the volume has 87 GB free, Explorer says something slightly different, and a quota aware application disagrees with both.
The solution: fsutil volume diskfree prints total and free bytes exactly, with no rounding, plus the quota adjusted figure that a per user quota would return to an application.
rem Exact byte counts, no rounding, no PowerShell startup cost
fsutil volume diskfree C:
rem Every volume on the box, including ones with no drive letter
fsutil volume list
The output pairs an exact byte count with a rounded unit on each line:
Total free bytes : 93,663,879,168 ( 87.2 GB)
Total bytes : 254,721,126,400 (237.2 GB)
Total quota free bytes : 93,663,879,168 ( 87.2 GB)
The third line is the interesting one. Where quotas are enabled and the account running has a limit, Total quota free bytes is smaller than Total free bytes, and it is the number an application is told when it asks how much room it has. A backup failing with a disk full error on a volume with visible free space is almost always this.
3. Build a sparse file and see why size on disk lies
The problem: a database or virtual disk file shows 40 GB in Explorer, the volume has 200 GB free, and yet backing that file up produces a 40 GB archive and fills the target.
The solution: the file is sparse. NTFS records the length but allocates clusters only where data has actually been written. fsutil sparse both proves it and lets you build one to see the behaviour first hand.
Build one in three steps. Create a small real file, mark it sparse, then extend its recorded length to 40 GB. Only the first megabyte is ever allocated.
rem 1 MB of real allocation to start with
fsutil file createnew C:\bat\test\sparse.dat 1048576
rem Marks the file sparse; from here NTFS stops allocating clusters it does not need
fsutil sparse setflag C:\bat\test\sparse.dat
rem Extend the recorded length to 40 GB without allocating anything
rem 40 * 1024 * 1024 * 1024 = 42949672960
fsutil file seteof C:\bat\test\sparse.dat 42949672960
rem Prove the attribute is set
fsutil sparse queryflag C:\bat\test\sparse.dat
rem Prove the volume did not lose 40 GB
fsutil volume diskfree C:
dir C:\bat\test\sparse.dat
queryflag answers in plain words, and dir reports the full 40 GB while the free space on the volume has moved by roughly one megabyte:
This file is set as sparse
07/09/2026 09:18 42,949,672,960 sparse.dat
fsutil sparse queryrange prints one entry per range that may contain nonzero data, offset and length in hexadecimal. On the file above that is a single range at offset 0 with length 0x100000, the 1 MB createnew allocated before the flag was set.
rem One line per allocated range; no lines at all means nothing is allocated
fsutil sparse queryrange C:\bat\test\sparse.dat
4. Reclaim space inside a file without deleting it
The problem: a capture file has 30 GB of stale content at the front and a few hundred megabytes you still need at the end. Truncating it loses the recent data, and the application holds the handle open so you cannot rewrite it.
The solution: fsutil file setzerodata tells NTFS that a byte range reads as zeros. On a sparse file that deallocates the clusters and the space comes back immediately, while the file keeps its length and its handle stays valid.
Punch out the megabyte allocated in the previous example. Offset and length are named arguments in decimal bytes, not positional ones.
rem offset and length are named arguments, decimal bytes
rem This releases the only allocated range in sparse.dat
fsutil file setzerodata offset=0 length=1048576 C:\bat\test\sparse.dat
rem queryrange now returns no ranges at all: nothing is allocated
fsutil sparse queryrange C:\bat\test\sparse.dat
rem The file still reports 40 GB
dir C:\bat\test\sparse.dat
setzerodata against a file that is not sparse. NTFS then does the literal thing and writes real zeros across the range, which is slow, generates the full amount of disk I/O, and frees nothing. Always confirm with fsutil sparse queryflag first.
5. Read the NTFS geometry before you blame the file system
The problem: a volume holding millions of small files is slow, or a restore onto a rebuilt server behaves differently from the original, and you need the cluster size and the MFT size.
The solution: fsutil fsinfo reports all of it without opening Disk Management.
rem Every mounted drive letter on the machine
fsutil fsinfo drives
rem Fixed, removable, network or CD-ROM, useful in a script before acting on a letter
fsutil fsinfo drivetype C:
rem Cluster size, sector size, MFT position and size
fsutil fsinfo ntfsinfo C:
drives is a single line; ntfsinfo is a long block, abridged here to the fields that matter in practice:
Drives: C:\ D:\ E:\
NTFS Volume Serial Number : 0xe660d46a60d442cb
Version : 3.1
Number Sectors : 0x000000001dc7ffff
Total Clusters : 0x0000000003b8ffff
Free Clusters : 0x00000000015a2c3b
Bytes Per Sector : 512
Bytes Per Cluster : 4096
Bytes Per FileRecord Segment : 1024
Mft Valid Data Length : 0x0000000018c00000
Bytes Per Cluster is the number to write down. At the 4096 default, two million 1 KB files waste roughly 6 GB in slack, and a volume formatted at 64 KB for a database wastes far more once small files land on it. Mft Valid Data Length divided by Bytes Per FileRecord Segment estimates how many file records the MFT has grown to hold.
fsutil fsinfo sectorinfo C: when you need the physical and logical sector sizes separately.
6. Turn off last access time updates on a busy file server
The problem: a file server spends measurable I/O writing a timestamp every time something is merely read, including every antivirus scan and every backup pass.
The solution: fsutil behavior reads and writes the volume wide NTFS settings. Query before you change anything, so you can put it back.
rem Read the current value first; note it down before changing it
fsutil behavior query disablelastaccess
rem 1 disables Last Access Time updates, 0 enables them
fsutil behavior set disablelastaccess 1
rem Also worth checking on SSD and thin provisioned SAN volumes:
rem 0 means trim and unmap notifications are being sent
fsutil behavior query disabledeletenotify
Each query prints the setting name and its value on one line:
DisableLastAccess = 0
NTFS DisableDeleteNotify = 0
ReFS DisableDeleteNotify is not currently set
disablelastaccess takes effect only after a restart, and on Windows 10 version 1803 and later the value can come back with a “System Managed” qualifier next to the number rather than a bare 0 or 1. Read the printed text rather than assuming the value is one character long. disabledeletenotify, by contrast, needs no restart and applies from the next unmap.
Cleanup
The Hidden gems and PowerShell sections below still use C:\bat\test, so run this once you have finished with the whole page. Nothing here touches anything outside that folder, with the single exception of fsutil behavior set in example 6, which is volume wide and is reversed by setting the value back to what the query reported.
del C:\bat\test\bigfile.dat
del C:\bat\test\sparse.dat
rd C:\bat\test
rem If you changed it in example 6, put it back to the value you noted
rem fsutil behavior set disablelastaccess 0
Hidden gems
createnew is instant because the data is never written, not because it is sparse
The trap that catches people first. fsutil file createnew and a sparse file both return in milliseconds and both report a large size, but only one leaves the volume alone. createnew allocates every cluster and simply leaves the valid data length at zero, so reads return zeros without touching the disk: the space is gone. A sparse file allocates nothing. Filling a disk on purpose calls for createnew; testing how an application handles large files without paying for the space calls for a sparse file.
setvaliddata can expose data you deleted years ago
fsutil file setvaliddata moves the valid data length forward without writing anything, so everything between the old and the new mark reads back as whatever those clusters physically contain: the previous occupant of that disk space. It exists for database engines that manage their own initialisation, and it needs the Perform volume maintenance tasks right (SeManageVolumePrivilege), which Administrators do not hold by default. Never point it at a file on a share.
rem Uses bigfile.dat from example 1; recreate it first if you already cleaned up
rem Requires SeManageVolumePrivilege; exposes raw on-disk content up to datalength
fsutil file setvaliddata C:\bat\test\bigfile.dat 4096
Sweep free space on every volume in one line
The combination trick. Pipe diskfree through find to select the line you want and let for /f pull the byte count out of it. Token 5 is the number, because the colon is a separate token in the default space delimited split.
rem Tokens on that line are: 1 Total 2 free 3 bytes 4 : 5 the number
rem The caret escapes the pipe so FOR passes it to the inner command
for /f "tokens=5" %i in ('fsutil volume diskfree C: ^| find "Total free bytes"') do @echo C: %i bytes free
"Total free bytes" is deliberate. It does not match Total bytes and it does not match Total quota free bytes, so exactly one line survives the filter. Inside a batch file, double the percent sign to %%i.
Check the USN journal before blaming the backup software
Backup agents, search indexers and replication engines read the USN change journal to find what changed since last time. If the journal is smaller than the change between two runs, entries roll off, the agent loses its place and falls back to a full scan. That is the usual explanation for an incremental job that quietly turns into a six hour full one.
rem Shows whether the journal is active, its maximum size and the current USN
fsutil usn queryjournal C:
fsutil usn deletejournal on a production volume to “reset” it. Every agent that was tracking the journal loses its position and reverts to a full scan, all at once. Query it, resize it with createjournal if it is too small, and leave delete alone.
PowerShell equivalent
PowerShell covers the reporting side of fsutil well and the allocation side not at all. Use it for free space and for finding sparse files, and keep fsutil for anything that changes how NTFS allocates.
Free space, in a form you can sort and filter:
# Get-Volume needs no elevation, unlike fsutil volume diskfree
Get-Volume |
Where-Object { $_.DriveLetter } |
Select-Object DriveLetter, FileSystem,
@{n='SizeGB'; e={ [math]::Round($_.Size/1GB, 1) }},
@{n='FreeGB'; e={ [math]::Round($_.SizeRemaining/1GB, 1) }}
Finding sparse files is the one every storage admin ends up wanting. The sparse attribute is bit 512 of System.IO.FileAttributes, so a bitwise AND isolates it. Bit 1024 is ReparsePoint, which is why a plain text match on the attribute list is unreliable here.
# 512 = FileAttributes.SparseFile. -band returns 0 for anything else,
# including ReparsePoint (1024), which a text match would confuse it with.
Get-ChildItem -Path C:\bat\test -Recurse -File -Force -ErrorAction SilentlyContinue |
Where-Object { $_.Attributes -band 512 } |
Select-Object FullName, Length, Attributes
Creating a file of an exact size works through the .NET stream API, the closest equivalent to createnew and still slower on large sizes:
# Equivalent to: fsutil file createnew C:\bat\test\ps.dat 1073741824
$f = [System.IO.File]::Create('C:\bat\test\ps.dat')
$f.SetLength(1GB)
$f.Close()
setzerodata or for setvaliddata. Those go through file system control codes with no cmdlet wrapper, so calling fsutil from a script is the supported route rather than a workaround.
Where this matters
- Backup targets that fill up early. A sparse source file reads back at its full length, so a backup written to a non sparse target needs the whole 40 GB even though the original occupied 200 MB.
- Reproducing a low disk space alert.
fsutil file createnewtakes a test volume to 95 percent in one command, so you can prove the monitoring rule fires before you rely on it in production. - Virtual machine disks that never shrink. Dynamically expanding VHDX files behave like sparse files at the host level, and the space only returns when the guest issues trim and the host honours it, which is what
disabledeletenotifyreports. - File servers with millions of small files. Cluster size from
fsinfo ntfsinfoplus last access updates frombehavior queryexplain most of the difference between a volume that performs and one that does not. - Incremental backups that turn into full ones. A USN journal that is too small for the daily change rate silently forces a full scan;
fsutil usn queryjournalis the two second check. - Migrations onto a rebuilt server. Comparing
fsinfo ntfsinfoon the old and new volumes catches a cluster size mismatch before the data is copied rather than after.
Tips and limitations
- Every subcommand on this page needs an elevated prompt. Microsoft states the requirement as membership in the Administrators group, and
setvaliddataadditionally needsSeManageVolumePrivilege. - Sparse files, hard links and reparse points are NTFS features. On ReFS, exFAT or FAT32 the relevant subcommands either fail or report the volume as unsupported.
- All sizes are decimal bytes. There is no KB, MB or GB suffix anywhere in fsutil, and passing one is accepted as a malformed number rather than rejected clearly.
- fsutil has no confirmation prompts and no undo.
volume dismount,usn deletejournaland8dot3name stripwithout/tall act immediately. behavior setchanges are volume wide or machine wide, not per folder, and several of them require a restart. Always run the matchingbehavior queryfirst and record the value.- The available subcommands vary by Windows version. Run
fsutilwith no arguments, or a subcommand with no parameter, to get the usage the local build actually supports.
Official documentation
- fsutil: Windows Commands | Microsoft Learn
- fsutil file: createnew, seteof, setzerodata and setvaliddata
- fsutil sparse: setflag, queryflag, queryrange and setrange
- fsutil behavior: every queryable and settable NTFS option
Related tools
- Windows Event Log Analyzer: for reading the Ntfs and disk entries that say what the file system reported before you started measuring.
- ROBOCOPY Command Builder: builds the copy that moves data off a volume once fsutil has told you how much of it is real.
Related guides
- chkdsk in Windows: switches and the online scan: what to do once fsutil or the event log says the volume has a problem.
- chkntfs in Windows: control the boot-time disk check: the dirty bit that
fsutil dirtyreads, and how to stop a check you did not schedule. - NTFS links in Windows compared: hard links, junctions and symbolic links, the subcommands this page leaves out.
- List symbolic links in Windows: where
fsutil hardlink listandfsutil reparsepoint queryfit into a real audit. - diskpart command guide: the layer below the file system, for when the volume itself is the problem.