Raspberry Pi (RPi) is a truly amazing and fascinating device, considering how much power you can get from this tiny device and its amazing versatility. The default and easiest way to set up an RPi is using an SD card, that you can provision using the official Raspberry Pi Imager

Unfortunately, SD cards are fairly slow in both read and write speed, especially compared to even inexpensive solid-state drives (SSDs). A typical SD card has the read/write spead of abouy 30Mb/sec, whereas SSD drives can easily do over 300MB/sec. SD cards are also lessi reliable than their SSD alternatives and generally not recommended for intensive write scenarios.

Raspberry Pi uses two main partitions: boot partition and root partition. As the names would suggest the former is used to load the operating system, where most runtime data is under the root partition. In this blog post we explain how to keep boot partition on the SD card, while moving the root partition to an SSD. In our opinion it gives you the best of both worlds, without any significant headache.

Please note that in such setup you only need a tiny SD Card of handful GBs in size, since most work will be switched to SSD, soon after the setup. 32GB was the smallest quality mini SD card we could find, and what we used, but if you have something even smaller, it will work just fine. 32GB was the smallest quality mini SD card we could find, and what we used, but if you have something even smaller, it will work just fine.

I also like using Ubuntu Servers everywhere (just a personal preference), so that’s what we use in all examples below. You may need to update some commands if you end-up using another Linux distribution.

TL;DR Synopsis

Basic idea is to install everything on SD card, then partition and format a blank SSD disk with ext4 filesystem. After which we duplicate SD Card’s root partition to the SSD, change the label of SSD’s disk to “usbssd” and tell RPi, in cmdline.txt config file, to use the disk with “usbssd” as its root partition, instead of the default, which is partition labeled “writable” on the SD card.

Detailed instructions

First, let’s make sure you know the device name for both your SD card and SSD drive. To see all attached devices, run: sudo lsblk -o UUID,NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,MODEL command in your terminal.

UUID                                 NAME        FSTYPE     SIZE MOUNTPOINT        LABEL       MODEL
                                     loop0       squashfs    59M /snap/core20/1627
                                     loop1       squashfs  57.9M /snap/core20/1614
                                     loop2       squashfs  40.6M /snap/snapd/16299
                                     loop3       squashfs    61M /snap/lxd/22761
                                     loop4       squashfs  41.5M /snap/snapd/17032
a7c221ca-e02d-4446-8229-6c6cbd888234 sda                   232.9G              
                                     mmcblk0              119.1G
5D5B-8026                            ├─mmcblk0p1 vfat       256M /boot/firmware    system-boot
a7c221ca-e02d-4446-8229-6c6cbd888234 └─mmcblk0p2 ext4     118.8G                   writable

In my case, the SSD is named sda and the SD card is named mmcblk0 with mcblk0p1 being the boot partition and mmcblk0p2 the root partition, respectively.

Now let’s partition and format our blank disk.

Partitioning And Formatting The Disk

To partition the disk, which in my case was blank, we need to use the fdisk utility:

> sudo fdisk /dev/sda  

Since mine was blank, I first created a new partition with the n command, then accepted all of the default settings, and finally saved the partition from memory to disk with the w comamnd, after which I exited fdisk with the q command:

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-488397167, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-488397167, default 488397167):

Created a new partition 1 of type 'Linux' and of size 232.9 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

In your case, your disk pay already have partitions, so make sure to adapt accordingly.

Once we have a single partition on the SSD, it’s time to format it:

> sudo mkfs.ext4 /dev/sda
mke2fs 1.45.5 (07-Jan-2020)
Found a dos partition table in /dev/sda
Proceed anyway? (y,N) y
Creating filesystem with 61049646 4k blocks and 15269888 inodes
Filesystem UUID: 73c7a0dd-91df-4397-8293-64b94f1f0ca0
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done

After the formatting successfuly completes, you may want to double-check the result with lsblk command: sudo lsblk -o UUID,NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,MODEL

Duplicating SD’s Root to SSD’s

Since Ubuntu was installed on the SD card, we need to copy all of the data on SD’s root partition, over to the SSD, before we make a swap. You can do it with a command dd using a syntax similar to:

> sudo dd if=/dev/mmcblk0p2 of=/dev/sda bs=1M status=progress
420478976 bytes (420 MB, 401 MiB) copied, 9 s, 46.6 MB/s

Please note that we are indicating the root partition of the SD card, after the “if” parameter, as the source and the single partition on the SSD as the destination.

This dd command will take a while, since it copies entire root partition of the SD card to SSD. This (in addition to lower cost) is another reason why you shouln’t buy a larg mini SD card, smaller it is quickly this step will complete.

Alternatively, you can use rsync for the same purpose, which under some conditions may be faster. RSync way of achieving what you need, would look like the following:

> sudo mkdir /mnt/ssd
> sudo mount /dev/sda /mnt/ssd 
> export src_dir="/"
> export dst_dir="/mnt/ssd"
> sudo rsync --force -rltWDEHXAgoptx --delete \
	--exclude '.gvfs' \
	--exclude '/dev/*' \
	--exclude '/mnt/clone/*' \
	--exclude '/proc/*' \
	--exclude '/run/*' \
	--exclude '/sys/*' \
	--exclude '/tmp/*' \
	--exclude 'lost\+found/*' \
$src_dir \

Once dd or rsync is done, we need to fix the label of the partition on the SD drive, since the dd comand would have set it to writable to mimic the SD car and rsync doesn’t set it at all. We do labeling with the following command:

> sudo e2label /dev/sda "usbssd"

The Swap Of partitions

Last, but most importantly, we need to edit /boot/firmware/cmdline.txt configuration file and replace root=LABEL=writable with root=LABEL=usbssd. Once it’s done, you need to restart your RPi, and after a restart, everything should work with the root partition now being an SSD.