I image my Home Assistant Pi monthly. The card is 32 GB but the actual data on it is maybe 6 GB, the OS, configs, Docker images, and a few months of logs. Without PiShrink, my IMG backup is 32 GB. With PiShrink, it’s about 7 GB. Five times smaller, same data preserved exactly. Multiply that across a 12-month archive of monthly backups (12 IMGs at 32 GB each = 384 GB without PiShrink, 84 GB with PiShrink), and the storage savings become significant.
PiShrink is a Linux bash script that’s been the standard tool for shrinking Pi OS IMG files since 2017. It resizes the partition inside the IMG to the minimum needed for the actual data, then sets a flag to auto-expand on first boot. End result: smaller archived backups, smaller distributables, smaller everything, while preserving the auto-fill behavior on the destination card. This article walks through the workflow on Windows (via WSL), troubleshooting common failures, and when to skip PiShrink in favor of just using a bigger destination card.
TL;DR: Make IMG backup with Win32 Disk Imager (Read with “Read Only Allocated Partitions”). Open WSL Linux. Install parted e2fsprogs. Download pishrink.sh from GitHub. Run sudo ./pishrink.sh /mnt/d/backups/pi.img. Done. IMG is now 30-70% smaller and ready to flash.
What PiShrink Actually Does
An IMG file from Win32 Disk Imager Read contains the full size of the source SD card, even with “Read Only Allocated Partitions” ticked, the IMG is the size of the largest allocated partition (which usually fills the card minus a tiny gap).
PiShrink does three operations:
1. Filesystem shrink. Calls resize2fs -M to shrink the ext4 filesystem inside the root partition to its minimum possible size (just slightly larger than the actual data).
2. Partition shrink. Updates the partition table (via parted) to make the root partition match the new filesystem size.
3. IMG truncate. Calls truncate to chop the unused tail off the IMG file, reducing the file size.
Plus one piece of magic: PiShrink injects a script into /etc/rc.local that auto-expands the partition back to fill the destination card on first boot. So your shrunk IMG works on any same-size or bigger card, with no manual steps after flashing.
The compression isn’t gzip-style; it’s actual reduction in needed bytes. Different from running 7-Zip on the IMG, which compresses the file but the IMG itself is still 32 GB once decompressed.
Setting Up WSL2 to Run PiShrink
PiShrink is a bash script using Linux-only tools (parted, e2fsck, resize2fs, sfdisk). It doesn’t run on Windows directly. You need WSL2 (Windows Subsystem for Linux 2).
If you don’t have WSL installed:
- Open admin PowerShell.
- Run
wsl --install. This installs WSL2 + Ubuntu by default. - Reboot when prompted.
- After reboot, Ubuntu installer launches automatically. Set username and password.
- You’re now in a Linux terminal.
If you already have WSL:
- Launch your Ubuntu (or other distro) shortcut. Bash terminal appears.
Install PiShrink dependencies:
sudo apt update
sudo apt install parted e2fsprogs uuid-runtime util-linux gawk -y
Takes 30 seconds. Now you have all the tools PiShrink uses.
Downloading PiShrink
PiShrink is a single bash script hosted on GitHub. Get the latest:
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
chmod +x pishrink.sh
That’s it. The script is ~700 lines of bash. No additional install needed.
Optionally move to a system path so it’s on $PATH:
sudo mv pishrink.sh /usr/local/bin/pishrink
Now you can call pishrink from anywhere instead of ./pishrink.sh.
Running PiShrink on Your IMG
Your IMG file is on Windows (e.g., D:\backups\pi-ha.img). WSL accesses Windows drives via /mnt/c/, /mnt/d/, etc.
Run PiShrink:
sudo pishrink /mnt/d/backups/pi-ha.img
Output (typical):
Creating new /etc/rc.local
pishrink.sh: pi-ha.img: Gathering data
pishrink.sh: pi-ha.img: Checking filesystem
e2fsck 1.46.5 (30-Dec-2021)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
rootfs: 234567/1900000 files (0.1% non-contiguous), 1456789/7600000 blocks
pishrink.sh: pi-ha.img: Shrinking filesystem
resize2fs 1.46.5 (30-Dec-2021)
Resizing the filesystem on /dev/loop1p2 to 1503127 (4k) blocks.
The filesystem on /dev/loop1p2 is now 1503127 (4k) blocks long.
pishrink.sh: pi-ha.img: Shrinking partition
Information: You may need to update /etc/fstab.
pishrink.sh: pi-ha.img: Shrinking image
pishrink.sh: pi-ha.img: Shrunk to 5.8G
Done. The IMG file at the original path is now smaller.
Took 60-180 seconds depending on IMG size and CPU.
Verify the Shrink Worked
Check the file size before and after:
ls -lh /mnt/d/backups/pi-ha.img
Should show the new (smaller) size.
Verify the IMG is still bootable by mounting it as a loop device and checking files:
sudo losetup -P /dev/loop99 /mnt/d/backups/pi-ha.img
sudo mkdir -p /mnt/img-test
sudo mount /dev/loop99p2 /mnt/img-test
ls /mnt/img-test
sudo umount /mnt/img-test
sudo losetup -d /dev/loop99
Should see /etc, /home, /usr, etc. If yes, IMG is intact.
Optional: re-flash the shrunk IMG to a test SD card with Win32 Disk Imager and boot the Pi. Confirm it auto-expands and runs normally.
Compression After PiShrink
PiShrink shrinks the IMG. After that, you can compress it further with 7-Zip, gzip, or xz for storage:
# From WSL
sudo apt install xz-utils
xz -9 /mnt/d/backups/pi-ha.img
# Produces pi-ha.img.xz
A typical 7 GB shrunk IMG compresses to ~2-3 GB with xz. Combined with PiShrink, that’s a ~10x reduction from the raw 32 GB unshrunk IMG.
Storage decision tree:
- Want fastest restore later: shrunk IMG, no compression. Just flash directly.
- Want smallest archive: shrunk IMG + xz compression. Decompress before flashing.
- Want medium tradeoff: shrunk IMG + 7z compression. Balance of size and decompress speed.
Common PiShrink Errors
“Operation not permitted” or permission errors. Forgot sudo. Re-run with sudo pishrink ....
“e2fsck: Bad magic number in super-block.” The IMG’s filesystem is corrupted or the IMG isn’t actually a Pi OS image. Try fsck first: sudo losetup -P /dev/loop99 file.img && sudo fsck -f /dev/loop99p2. If fsck repairs, retry PiShrink.
“resize2fs: New size smaller than minimum.” The filesystem is already at minimum size. Nothing to shrink. The IMG is as small as it can get.
“parted: Error: Can’t have a partition outside the disk!” The IMG file’s apparent size doesn’t match the partition table claims. Usually means a previous PiShrink run was interrupted. Re-create the IMG from the source SD card.
WSL can’t access /mnt/d/. Drive D: isn’t mounted in WSL. Check ls /mnt/ for available mounts. Or copy the IMG to your WSL home directory first.
Out of disk space during shrink. PiShrink needs temporary space ~equal to the IMG size. If WSL’s filesystem is full, free space first.
Auto-Expand Verification
PiShrink injects auto-expand into /etc/rc.local. Verify it’s there:
sudo losetup -P /dev/loop99 /mnt/d/backups/pi-ha.img
sudo mount /dev/loop99p2 /mnt/img-test
cat /mnt/img-test/etc/rc.local
sudo umount /mnt/img-test
sudo losetup -d /dev/loop99
Should see PiShrink’s expand-rootfs script in there. If missing, PiShrink didn’t successfully add it; the IMG won’t auto-expand on first boot. Manual expansion via raspi-config is required after first boot.
Automating PiShrink With a PowerShell Script
For repeat backups, automate the workflow:
# PowerShell on Windows
$img = "D:\backups\pi-ha-$(Get-Date -Format yyyy-MM-dd).img"
# Win32 Disk Imager Read happens manually first.
# Then trigger PiShrink + compression via WSL:
wsl bash -c "sudo pishrink /mnt/d/backups/pi-ha-$(date +%Y-%m-%d).img"
wsl bash -c "xz -9 /mnt/d/backups/pi-ha-$(date +%Y-%m-%d).img"
$hash = (Get-FileHash -Path "$img.xz" -Algorithm SHA256).Hash
"$hash $(Split-Path "$img.xz" -Leaf)" | Out-File "$img.xz.sha256"
Write-Host "Backup complete: $img.xz with SHA256 $hash"
Schedule this via Task Scheduler to run after each Win32DI manual Read. Three commands, IMG is shrunk, compressed, hashed, ready for NAS upload.
Add an rsync-to-NAS step at the end for full automation. Total handoff: ~5 minutes per backup.
Workflow: Backup → Shrink → Archive
End-to-end monthly backup workflow I use:
- Shut down Pi cleanly. Pop SD card.
- Plug SD into Windows PC via USB reader.
- Win32 Disk Imager Read with “Read Only Allocated Partitions” ticked. Save as
pi-ha-2026-04-20.img. - Generate SHA256 hash. Save as sidecar
pi-ha-2026-04-20.img.sha256.original. - Open WSL.
sudo pishrink /mnt/d/backups/pi-ha-2026-04-20.img. - Compress:
xz -9 /mnt/d/backups/pi-ha-2026-04-20.img. - Generate hash of the compressed file. Save sidecar
.xz.sha256. - Rsync to NAS:
rsync -avh /mnt/d/backups/ user@nas:/mnt/pool/pi-backups/. - Pi boots back up with original SD card.
Total time: 25 minutes from start to finish. Result: a ~2-3 GB compressed shrunk IMG safely on NAS, byte-verified.
To restore: decompress, flash with Win32 Disk Imager, boot Pi. Pi auto-expands on first boot. 15 minutes total.
When to Skip PiShrink
PiShrink isn’t always necessary:
- You’re flashing to the same-size or larger card. Just write the unshrunk IMG. Pi boots fine, partition fills the card automatically (Pi OS has its own auto-expand on first boot for fresh installs).
- You’ll only flash this IMG once and discard. Why bother shrinking?
- Storage is cheap and you have plenty. A few extra GB on a NAS is meaningless.
- Time-sensitive backup. Skip PiShrink for now; do it later when you have time.
PiShrink is most valuable when:
- Archiving many monthly/quarterly backups.
- Distributing pre-configured Pi images to others (smaller download).
- Restoring to a smaller card than the source (only way it’ll fit).
- Cloud backup where storage costs scale with size.
How PiShrink Auto-Expand Works (Technical)
The auto-expand magic is one of the cleverer bits of PiShrink. Here’s what it does:
PiShrink writes a small bash script to the IMG’s /etc/rc.local. On first boot, rc.local runs as root before the GUI starts. The script:
- Detects the actual SD card size at boot (using
blockdev --getsz). - Compares to the current partition size.
- If card is bigger than partition, runs
parted resizepart 2 100%to extend the root partition to fill the card. - Runs
resize2fs /dev/mmcblk0p2to expand the ext4 filesystem to fill the partition. - Removes itself from rc.local so it doesn’t run again on subsequent boots.
- Reboots to apply changes cleanly.
Result: Pi looks like a normal install with full filesystem on next boot. The user never sees the auto-expand process unless they’re watching the boot log.
This is the core feature that makes PiShrink production-ready, not just smaller IMGs but smaller IMGs that automatically grow back to fill the destination card.
PiShrink Alternatives
Other tools that do similar IMG shrinking:
- Pi-Safe (pi-safe.com): GUI alternative, runs on Linux. More user-friendly but less scriptable.
- SD Card Copier (built into Pi OS Desktop): clones SD to SD on the running Pi, can target a smaller card. Different workflow (live, not file-based).
- Manual resize2fs + truncate: if you want PiShrink’s effect without the script. More control, more error-prone.
- btrfs send/receive: for btrfs-based images. Different filesystem, different tools.
For 95% of Pi user workflows, PiShrink is the right tool. The alternatives have niche use cases.
Restoring a PiShrunk IMG
Flashing a shrunk IMG is identical to flashing any IMG with Win32 Disk Imager:
- Insert blank SD card (same size as original, or larger).
- Win32 Disk Imager → point at the shrunk IMG → pick SD → Write.
- Eject. Insert into Pi. Power on.
- Pi boots. PiShrink’s rc.local script runs, expanding the partition to fill the card. Takes 30-60 seconds. Pi reboots automatically.
- Pi is now running, with the partition fully expanded.
If PiShrink’s expand script didn’t run (rare), you can manually expand: sudo raspi-config → Advanced Options → Expand Filesystem → reboot.
See our Pi SD restore guide for the full restore workflow.
Caveats and Edge Cases
PiShrink only works on Pi OS images. Specifically, images with the standard Pi OS layout (boot FAT32 + root ext4). Custom Pi distros (DietPi, RetroPie sometimes) may have additional partitions PiShrink doesn’t handle correctly.
Doesn’t work on read-only filesystems. If you’ve made the Pi root read-only (some Pi setups for kiosks), PiShrink can’t shrink it.
Doesn’t shrink LUKS-encrypted partitions. Encrypted Pi setups need decryption first.
Doesn’t compress; only shrinks. The IMG is smaller in bytes but still uncompressed. Pair with xz for further compression.
Auto-expand uses /etc/rc.local. If you’ve already customized rc.local for your own purposes, PiShrink may overwrite or break your script. Back up rc.local first if it has anything important.
Real Storage Numbers From My Backup Archive
Concrete data from my own archive, twelve months of monthly Pi backups across three Pis (Home Assistant, OctoPi, Pi-hole):
| Backup Type | Per-IMG Size | 12-Month Total |
|---|---|---|
| Full IMG (no PiShrink, no compression) | 32 GB | 1152 GB |
| “Read Only Allocated” IMG (no PiShrink) | ~28 GB | ~1008 GB |
| PiShrunk IMG (no compression) | ~7 GB | ~252 GB |
| PiShrunk + xz compressed | ~2.3 GB | ~83 GB |
Going from 1152 GB to 83 GB is a ~14x reduction. On a NAS that’s the difference between filling a 1 TB drive in 10 months vs filling it in 12+ years. Massive practical impact.
Trade-off: each backup takes ~3 extra minutes for PiShrink + xz compression. Acceptable.
FAQ
Why do I need WSL? Can’t PiShrink run on Windows directly?
PiShrink uses Linux-only tools (resize2fs, parted) that don’t have Windows ports. WSL2 is the easiest way to run them. Alternatively, run PiShrink on a real Linux machine or boot from a Linux Live USB.
How much will PiShrink reduce my IMG?
Depends on how much actual data is on the source SD. A 32 GB SD with 6 GB used = ~7 GB shrunk IMG (a 78% reduction). A 32 GB SD with 25 GB used = ~26 GB shrunk IMG (only 19% reduction). Mostly-empty cards shrink dramatically; mostly-full cards don’t shrink much.
Will PiShrink work on Windows ISO files?
No. PiShrink is specifically for Pi OS (ext4 root partition + FAT32 boot). Windows ISOs use different filesystems. Don’t run PiShrink on Windows ISOs.
What if my Pi setup uses btrfs or zfs instead of ext4?
PiShrink doesn’t support btrfs or zfs out of the box. You’d need to manually shrink the filesystem with btrfs-specific tools (btrfs filesystem resize) and then truncate the IMG yourself.
How do I update PiShrink to a newer version?
Re-download the latest pishrink.sh from GitHub. Replace the old script with the new one. PiShrink doesn’t have a versioning/update mechanism, just download fresh whenever you want the latest.
Can I PiShrink an IMG made by Raspberry Pi Imager’s clone feature?
Pi Imager doesn’t have a clone-to-IMG feature. Win32 Disk Imager Read or Linux dd are the tools for that. Once you have the IMG, PiShrink works regardless of how the IMG was created.
Does PiShrink modify my original SD card?
No. PiShrink only modifies the IMG file. The original SD card is untouched. PiShrink is non-destructive to your live setup.
Why does my shrunk IMG fail to boot when flashed?
Possible: filesystem was corrupted before PiShrink ran (run fsck first), partition table got mangled (re-create IMG from source), or the IMG was corrupted during PiShrink (re-run). Verify with loop-mount and ls /mnt before flashing.
Can I PiShrink an IMG that contains Docker containers / large databases?
Yes. PiShrink doesn’t care what’s inside the filesystem, just shrinks to minimum that fits the data. Large databases reduce shrinkage potential, but PiShrink still works.
What happens if I PiShrink the same IMG twice?
Second run says “filesystem is already at minimum size” and exits. No harm. The IMG is as small as PiShrink can make it after the first run.
Is there a Windows GUI for PiShrink?
Not officially. Pi-Safe has a Linux GUI but no Windows version. Some community tools wrap PiShrink in PowerShell GUIs. PiShrink itself is command-line only.
Should I PiShrink before or after compressing?
PiShrink first, then compress. Shrinking reduces the byte count; compression squeezes the remaining bytes further. Doing compression first means PiShrink can’t process it (it expects a raw IMG, not .xz/.7z).
Wrapping Up
PiShrink is the maker community’s secret weapon for Pi backups. 5 minutes of WSL setup, then every backup gets 30-70% smaller automatically. For Pi users archiving regular backups, the storage savings add up fast. For everyone else, it’s optional but useful. Pair with our SD card backup guide and Pi restore guide for the complete Pi backup workflow.
Related Guides
Pair this guide with the rest of the Win32 Disk Imager knowledge base. These cover the adjacent workflows you’ll hit when working with disk images, bootable USBs, and Windows partition management.
- How to Back Up an SD Card to an IMG File on Windows — Back up a Raspberry Pi SD card to an IMG file on Windows — full Read walkthrough, PiShrink compression, and a backup-schedule template.
- How to Restore a Raspberry Pi SD Card from a Backup IMG — Restore your Pi SD card from an IMG backup with Win32 Disk Imager. Auto-expand filesystem, larger-card upgrades, post-restore troubleshooting.
- How to Use Win32 Disk Imager — Complete Beginner Guide — The full reference for the Win32 Disk Imager tool itself — install, UI walkthrough, and common workflows.
- Win32 Disk Imager: Not Enough Space on Disk — Causes + Fixes — Why your 32 GB IMG won’t fit on your 32 GB SD card — PiShrink, SD card size variance, counterfeit detection, and the Read destination-space trick.