# PiShrink: shrink a Raspberry Pi .img before you write it to an SD card

> PiShrink is a bash script that shrinks the last partition of a Pi image and leaves it to expand again on first boot. It is a one-command tool with a narrow target, and the documentation is honest about where it stops.

**Drewsif/PiShrink** — Make your pi images smaller!

- Repository: https://github.com/Drewsif/PiShrink
- Stars: 4,116 · Forks: 698
- Language: Shell
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/drewsif-pishrink

## The problem PiShrink solves: a 30G image on a 32G card

A Raspberry Pi image written by a tool like Win32 Disk Imager is usually as large as the card it came from, not as large as the data on it. The README's own example shows the gap: a 30G image shrinks to 3.1G. Most of that space is empty blocks that the filesystem never wrote to but the raw image still carries. Copying, uploading, archiving and compressing that image all pay for the empty space.

PiShrink targets that specific waste. It is a bash script that runs against an image file on a host machine, not against a live Pi. The README states the goal plainly: shrinking makes putting the image back onto the SD card faster, and the shrunk images compress better. The second half matters more than it sounds. A 3.1G image compresses to a fraction of what a 30G image does, so the same script improves both the write step and the storage step.

The audience is narrow on purpose. This is for people who maintain Pi images for distribution or for repeated reflashing: a class set of cards, a kiosk build, a home-lab base image. If you flash one card once, the setup cost of installing the script and its dependencies is not worth it. If you flash the same image twenty times, it is.

## How the shrink and auto-expand cycle actually works

The script operates on the last partition of the image, and the README is explicit that the partition must be ext2, ext3 or ext4. Anything else and it cannot shrink the image. That constraint follows from the tools it drives: the example output shows e2fsck running its five passes, then resize2fs reporting the filesystem on /dev/loop1 is now 773603 blocks long. So the data flow is: attach the image, check and repair the filesystem, resize the filesystem down to the used blocks, then truncate the image file to match.

The second half of the design is what makes the result usable. A shrunk image whose partition table still claims the old size would boot into a filesystem smaller than the card. PiShrink instead leaves the image set to expand on first boot, so the Pi grows the filesystem back to the full card. The -s flag disables that: with -s the script does not expand the filesystem when the image is booted the first time, which is what you want if you are shipping a fixed-size image rather than a card-filling one.

Two conditions govern whether auto-expansion runs. The README says that if the last partition is not the root filesystem partition, auto resizing will not run on boot. And on a Systemd distro you should ensure /etc/rc.local compatibility is enabled, because that is the mechanism the resize depends on. Neither is checked by the script; both are the user's problem. That is the sharpest edge in the whole tool: it will happily shrink an image that then never expands.

## Installing PiShrink on Linux, WSL 2 and macOS

On Debian or Ubuntu, install the runtime dependencies first. The README gives this exact command:

```bash
sudo apt update && sudo apt install -y wget parted gzip pigz xz-utils udev e2fsprogs
```

Then fetch the script, make it executable and put it on your PATH:

```bash
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
chmod +x pishrink.sh
sudo mv pishrink.sh /usr/local/bin
```

A first real use is a single command against an image you have already copied somewhere with free space:

```bash
sudo pishrink.sh pi.img
```

You should see e2fsck's passes, then resize2fs output, then a line in the shape of the README's example: Shrunk pi.img from 30G to 3.1G. Adding -z or -Z compresses afterwards with gzip or xz, and -a runs the compression in parallel using multiple cores. If you pass a second filename, the script copies the first image and works on the copy, which the README notes requires enough space for a full copy.

On Windows, the README routes you through WSL 2: run wsl --install -d Debian in an Administrator command prompt, open the Debian app, install the same apt packages, then follow the Linux steps. Your C: drive appears at /mnt/c/. On macOS the instructions are community-sourced and use Docker: clone the repository, run docker build -t pishrink ., then add a shell alias that runs the container with --platform linux/amd64 on Intel or --platform linux/arm64 on Apple Silicon, --privileged=true, and a volume mount of the current directory to /workdir. The README warns that you must cd into the directory holding your .img file first, because the alias mounts the working directory and absolute paths should not be used.

## Where PiShrink fails or is the wrong tool

The ext2/ext3/ext4 requirement is the first hard limit, and it rules out a common layout. Many Pi images end in a FAT32 boot partition, especially custom builds where the root filesystem is not last. PiShrink shrinks the last partition only, so on such an image it either cannot work or produces an image that will not auto-expand. Check your partition layout before you build a workflow around this.

Environment problems are the second category. The README states that running PiShrink inside VirtualBox against a Shared Folder is known to cause issues: you can copy the image onto the VM from the shared folder, but shrinking directly from it does not work reliably. On Ubuntu, an out-of-date e2fsck produces errors about metadata_csum, and the README's fix is to use Ubuntu 16.10 or later rather than patch around it. The related search phrase "pishrink parted is not installed" points at the same class of failure: the script depends on host tools, and a missing one stops it.

There is also a data-safety dimension the README does not address. The script runs e2fsck against the image and can repair it, with -r using an advanced repair option if the normal one fails. Repairing a filesystem is a modifying operation, and the README does not document rollback. If you pass a second filename you get a copy to fall back on; if you do not, you are working on your only copy. The -d flag writes a pishrink.log for problem analysis, which is the only diagnostic trail the tool offers. For an image you cannot regenerate, keep the original.

## How PiShrink differs from general image tools

The obvious comparison is a general-purpose imaging or partition tool such as parted or a disk-imaging utility. Those operate on partitions and filesystems as primitives: you inspect the layout, resize a partition, resize the filesystem inside it, and truncate the file yourself. They are more flexible and know nothing about Raspberry Pi boot behaviour. PiShrink is the opposite trade: it hardcodes the Pi-specific sequence, including the auto-expand-on-first-boot step that a generic tool would leave to you, and in exchange it refuses images whose last partition is not ext.

A second comparison is compression alone. gzip or xz on an untouched 30G image does reduce it, but the empty blocks still cost compression time and still produce a larger archive than the same image after shrinking. PiShrink's -z, -Z and -a flags exist precisely because the two steps compose: shrink first, compress second. If your only goal is a smaller file to store and you never write it back to a card, plain xz gets you most of the way without needing loop devices or privileged access. If you do write it back, the shrink step is what cuts the write time.

The dependency set tells you what kind of tool this is. The Dockerfile builds from debian:bookworm and installs wget, parted, gzip, pigz, xz-utils, udev and e2fsprogs, then copies pishrink.sh to /usr/local/bin/pishrink and sets it as the entrypoint. That is a thin wrapper around standard Linux filesystem utilities, not a custom image format.

## Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-05-10. The most recent release listed is v26.03.16 from 2026-03-16, with v24.10.23 and v24.10.10 before it. The release cadence is irregular rather than steady, which fits a script whose behaviour depends on the host's e2fsprogs and parted rather than on its own code.

Upgrade cost is low by design. Installation is a single file moved to /usr/local/bin, so upgrading means re-fetching pishrink.sh and replacing it; there is no package manager state, no service to restart and no configuration file to migrate. The script checks GitHub for a new release unless you pass -n, which is the one piece of network behaviour you may want to disable in an offline build environment.

Two environment variables act as configuration: PISHRINK_GZIP and PSHRINK_XZ, which the README says overwrite the default options for the gzip and xz compressors. Note the spelling difference between the two names as documented; copy them exactly rather than assuming they share a prefix. Compression runs through pigz with -f9 and xz with -T0 when -a is used, so parallel compression depends on pigz being present, which the apt line installs.

The project is MIT licensed. That is permissive, and it means you can ship the script inside your own build tooling or a container image without a copyleft obligation. It says nothing about the licence of the images you process or the tools the script invokes; those are separate questions and not ones this repository answers.

## Conclusion

Adopt PiShrink if you build Raspberry Pi images on a Linux host or in WSL 2 and your last partition is ext2, ext3 or ext4, because the shrink-and-expand cycle is the whole point of the tool and it costs one command. Do not adopt it if your image ends in a FAT32 boot partition or another non-ext filesystem, if you need to keep a fixed partition size across devices, or if you cannot run privileged operations against a loop device. Verify three things before you rely on it: that your image's last partition is the root filesystem, that the host has e2fsck and resize2fs from e2fsprogs new enough for your image's metadata_csum feature, and that you kept the original .img until the shrunk copy has booted once on real hardware.

## FAQ

### What does PiShrink do?

It is a bash script that shrinks the last partition of a Raspberry Pi image and leaves the filesystem set to resize to the full SD card on first boot. The README gives an example of a 30G image shrinking to 3.1G.

### How do I install PiShrink?

On Debian or Ubuntu, install wget, parted, gzip, pigz, xz-utils, udev and e2fsprogs with apt, then download pishrink.sh, make it executable and move it to /usr/local/bin. Windows users go through WSL 2 with Debian, and macOS users build the Docker image and add a shell alias.

### How do I use PiShrink?

Run sudo pishrink.sh pi.img on the image file. Optional flags include -s to skip filesystem expansion on first boot, -v for verbose output, -n to disable update checking, -r for advanced filesystem repair, -z or -Z to compress with gzip or xz, -a for parallel compression, and -d to write a pishrink.log debug log.

### Can PiShrink shrink any .img file?

No. The README states it shrinks the last partition of the image, and that if the partition is not ext2, ext3 or ext4 it cannot shrink the image. If the last partition is not the root filesystem partition, auto resizing will not run on boot either.

## Sources

- [Drewsif/PiShrink on GitHub](https://github.com/Drewsif/PiShrink)
- [Issues](https://github.com/Drewsif/PiShrink/issues)
- [License: MIT](https://github.com/Drewsif/PiShrink/blob/master/LICENSE)
- [README](https://github.com/Drewsif/PiShrink/blob/master/README.md)
- [Releases](https://github.com/Drewsif/PiShrink/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/drewsif-pishrink
