VHD File Documentation
Summary
A VHD (Virtual Hard Disk) file stores an entire hard disk — partition table, filesystem, an installed operating system and every file — inside one host file. It is Microsoft’s virtual-disk format, used by Hyper-V, VirtualBox and old Virtual PC, and by Windows itself for backups and bootable disks. Its MIME type is application/x-vhd. On Windows you can attach a .vhd in Disk Management to read it as a drive letter, or boot it in a VM.
Technical details
| Feature | Value |
|---|---|
| Full name | Virtual Hard Disk |
| File extension | .vhd |
| MIME type | application/x-vhd |
| Format type | Virtual disk-image container (binary) |
| Developer | Connectix, then Microsoft (acquired 2003) |
| Introduced | Connectix Virtual PC, early 2000s; spec published 2006 |
| Specification | Microsoft VHD Image Format Specification (Open Specification Promise, 2006) |
| Open standard | Yes — published under the Open Specification Promise |
| Disk types | Fixed, dynamically expanding, differencing |
| Maximum size | 2 TB (2040 GB) |
| Byte order | Big-endian (network byte order) in the footer/header |
| Footer size | 512 bytes, appended at end of file |
| Footer cookie | conectix (63 6F 6E 65 63 74 69 78) |
| Dynamic-header cookie | cxsparse |
| Sector size | 512 bytes |
| Successor | VHDX (Windows 8 / Server 2012, up to 64 TB) |
| Native Windows use | Disk Management attach, image backup, native VHD boot |
| Related extensions | .vhdx, .avhd, .vmdk, .vdi, .iso |
| Specification URL | learn.microsoft.com/openspecs/windows_protocols/ms-vhdx/ |
What is a VHD file?
VHD stands for Virtual Hard Disk. A .vhd file is a byte-for-byte image of a complete hard disk — its master boot record or GUID partition table, one or more partitions, the filesystem inside them, an installed operating system and every file — stored as a single ordinary file on a host disk. The format originated with Connectix Virtual PC in the early 2000s. Microsoft acquired Connectix in 2003 and published the VHD Image Format Specification under its Open Specification Promise in 2006, which is why VirtualBox, VMware, QEMU and other tools can read and write it despite VHD being a Microsoft format.
A VHD is not a document and has no application data of its own; it is a disk that happens to live in a file. When a hypervisor or Windows “attaches” it, the sectors inside the file are presented to the system exactly as if a physical drive had been plugged in. Everything below describes how those sectors are wrapped: the 512-byte footer that identifies the disk, the sparse-disk header that lets a dynamic image grow on demand, and the block allocation table that maps virtual sectors to their real location in the file.
The 512-byte footer: conectix, geometry and disk type
Every VHD ends with a 512-byte footer (a “hard disk footer”). It is placed at the end rather than the start for a historical reason: a fixed VHD is just a raw sector-by-sector image of the disk with the footer glued on, so an old tool that ignored the footer could still read the raw image. The footer begins with the 8-byte cookie conectix, and all its multi-byte integers are big-endian.
VHD hard disk footer (512 bytes, big-endian)
offset size field
0 8 cookie "conectix"
8 4 features bit 1 = reserved (usually 0x00000002)
12 4 file format version 0x00010000 (v1.0)
16 8 data offset for dynamic/diff: file offset of the dynamic header
(0xFFFFFFFFFFFFFFFF for a fixed disk)
24 4 time stamp seconds since 2000-01-01 00:00 UTC
28 4 creator application e.g. "vpc ", "win ", "qemu"
32 4 creator version
36 4 creator host OS "Wi2k" (Windows) or "Mac "
40 8 original size bytes
48 8 current size bytes
56 4 disk geometry cylinders (2) + heads (1) + sectors/track (1)
60 4 disk type 2 = fixed, 3 = dynamic, 4 = differencing
64 4 checksum one's-complement sum of the footer
68 16 unique ID 128-bit UUID identifying this disk
84 1 saved state
85 427 reserved (zero)
The disk type field at offset 60 is the switch that decides how the rest of the file is interpreted: 2 for a fixed disk, 3 for a dynamically expanding disk, and 4 for a differencing (child) disk. The data offset at offset 16 points to the sparse header for types 3 and 4, and is set to all-ones for a fixed disk that has no such header. disk geometry packs a CHS description (cylinders, heads, sectors-per-track); the VHD CHS formula tops out at 65535×16×255 sectors, one reason the format is capped at 2 TB. The checksum is a simple one’s-complement sum of every footer byte with the checksum field itself treated as zero, so a reader can detect a corrupted footer before trusting the geometry.
Fixed, dynamic and differencing disks
The three disk types trade allocation against overhead. A fixed disk reserves its full virtual size on the host up front: a 40 GB fixed VHD is a 40 GB file from the moment it is created, plus the 512-byte footer. Reads and writes go straight to the matching offset in the file with no indirection, which is why Azure historically required fixed VHDs for VM disks — there is no per-block lookup to slow I/O down.
A dynamically expanding disk starts small and grows as the guest writes data. The file holds only the blocks that have actually been written, so an almost-empty 40 GB dynamic VHD may be a few megabytes. A differencing disk goes one step further: it is a child that stores only the sectors that differ from a read-only parent VHD. Reads fall through to the parent for any block the child has not modified, which makes differencing disks the mechanism behind snapshots and behind cloning many machines from one golden image. Both dynamic and differencing disks need extra bookkeeping, and that is what the sparse header and block allocation table provide.
The dynamic disk header (cxsparse) and the block allocation table
For dynamic and differencing disks, a copy of the footer sits at offset 0, and immediately after it comes a 1024-byte dynamic disk header whose cookie is cxsparse. This header describes how the sparse image is laid out.
Dynamic disk header (1024 bytes, big-endian)
offset size field
0 8 cookie "cxsparse"
8 8 data offset 0xFFFFFFFFFFFFFFFF (reserved)
16 8 table offset file offset of the Block Allocation Table (BAT)
24 4 header version 0x00010000
28 4 max table entries number of blocks in the disk
32 4 block size bytes per block (default 0x00200000 = 2 MB)
36 4 checksum
40 16 parent unique ID UUID of the parent (differencing disks)
56 4 parent time stamp
64 4 reserved
68 512 parent unicode name
580 192 parent locator entries (8 × 24 bytes: where to find the parent)
772 256 reserved
The disk is divided into fixed-size blocks, 2 MB by default. The block allocation table (BAT), found at table offset, is an array of 32-bit sector offsets, one entry per block. An entry of 0xFFFFFFFF means that block has never been written and reads as zeros (or falls through to the parent for a differencing disk); any other value is the sector offset in the file where that block lives. Each allocated block is preceded by a sector bitmap that marks which 512-byte sectors within the block actually contain data. To read a guest sector, a parser divides its address by the block size to index the BAT, checks the bitmap, and jumps to the resolved file offset — the same indirection a real sparse file uses, done in user space by the VHD reader.
Differencing disks add the parent unique ID and parent locator fields so a child can find its parent by UUID and by path. If the parent is moved or its UUID changes, the chain breaks and the child cannot be mounted, which is the usual cause of a “parent not found” error.
Attaching, backing up and booting from a VHD in Windows
VHD is not only a virtual-machine format; Windows treats it as a first-class disk. Disk Management’s Action › Attach VHD mounts a .vhd as a real drive letter (on Windows 8 and later, double-clicking the file in Explorer does the same), so its filesystem can be browsed and copied without any hypervisor. Older Windows image backups (“Complete PC Backup”) wrote system images as VHDs, and Windows supports native VHD boot: the physical machine boots straight from an OS installed inside a VHD file, configured through bcdedit. Because the footer records the exact geometry and the BAT resolves every block, the mounted disk behaves identically whether it is opened by Hyper-V, by Disk Management, or by guestmount on Linux.
The format’s two hard limits — the 2 TB ceiling from the CHS geometry and its relative fragility if power is lost mid-write — are what drove Microsoft to introduce VHDX with Windows 8 and Server 2012. VHDX raises the maximum to 64 TB and adds an internal log that journals metadata so an image survives a crash. Converting between the two is routine with PowerShell’s Convert-VHD, and VHD remains common for compatibility and for older Azure disks.
Converting to VMDK, VDI and raw, and why VHD to ISO is impossible
Because a VHD is a hard-disk image, it converts cleanly to other hard-disk-image formats: VMDK for VMware, VDI for VirtualBox, or a flat raw/img sector image. qemu-img convert -O vmdk in.vhd out.vmdk and VBoxManage clonemedium both do this by walking the BAT and writing each block out in the target layout. What does not work is “VHD to ISO”: an ISO is an optical-disc image built around the ISO 9660/UDF filesystem, whereas a VHD is a whole hard disk with its own partition table. There is no meaningful sector-level mapping between the two. To extract files, attach the VHD and copy them, or open it read-only with 7-Zip; to build a bootable ISO you have to author it from the operating system separately. Sites advertising a “VHD to ISO converter” are mislabelling one of these other operations.
Frequently asked questions
Why is the conectix signature not at the start of a fixed VHD?
Because a fixed VHD is a raw, sector-by-sector image of the disk with the 512-byte footer appended at the end. Keeping the raw image first meant early tools could treat the file as a plain disk image and ignore the footer. Dynamic and differencing VHDs, which cannot be read as a flat image, keep a second copy of the footer at offset 0 so they can still be identified there.
What block size does a dynamic VHD use, and why does it matter?
The default block size recorded in the dynamic disk header is 2 MB (0x00200000). It sets the granularity at which the file grows: the first write anywhere inside a 2 MB region allocates that whole block plus its sector bitmap. A larger block size means fewer BAT entries but more slack; a smaller one tracks space more tightly at the cost of a bigger table.
How is VHD different from VHDX at the file level?
VHD identifies itself by a conectix footer and is capped at 2 TB with no crash-recovery log. VHDX starts with a vhdxfile signature at offset 0, allocates via a region table and BAT that scale to 64 TB, stores a logical sector size for 4K-native disks, and journals metadata in an internal log so the image survives sudden power loss.
References
- Microsoft Learn — [MS-VHDX] and the VHD Image Format Specification
- Microsoft Learn — Convert-VHD (Hyper-V PowerShell)
- QEMU — qemu-img disk image utility
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.