Google Photos is a very comfortable closet. With Immich you build the closet yourself, including the floor, and you also keep the key to the spare closet in another house. This guide does the planning before the first photo moves.
The short answer
What does Immich need to run? The project's documentation names at least 2 CPU cores and 6 GB of RAM, and recommends 4 cores and 8 GB [1]. On 4 GB you can run it with machine learning switched off [1]. The database belongs on local SSD storage, never on a network share [1]. Plan the storage at about 1.1 to 1.2 times your original library, and plan about three times your library across server, local backup and offsite copy (our derivation, details below). The backup rule that matters: Immich's own database dumps contain only metadata, so you must copy the photo folders yourself, and the project recommends doing the database first and the files second [6]. We say below what that costs per year, with dates and sources, and where self-hosting does not save money.
How it works
- What actually runs. The compose file of release v3.3.5 starts four containers: the Immich server (web, API and jobs, port 2283), a machine learning container, a Valkey instance as job broker, and a PostgreSQL database with the VectorChord extension [3]. Machine learning (ML) means the models that read your photos: smart search by content (CLIP) and face detection [10][22]. The docs list the CLIP search as running on top of Postgres, which is why the database matters so much [10].
- Pin the version. The latest release we found on 25 Oct 2026 is v3.3.5 from 21 Oct 2026 [4]. The example
.envfile setsIMMICH_VERSION=v3, a tag that follows the current major version [2][5]. The compose file falls back toreleaseif the variable is empty [3]. We would pin a full version such asv3.3.5instead, because upgrades should be your decision. The project promises breaking changes only in major versions, requires the server to match the app's major version, advises you to upgrade mobile clients first, and does not support downgrades [5]. We did not pull the images ourselves; the tag format comes from the project's documentation and release list [2][4]. - CPU, RAM and where it runs. Besides the minimums above, the docs say Immich runs on amd64 and arm64, and that the ML container on amd64 needs the x86-64-v2 instruction level, which most CPUs since about 2012 provide [1]. A full virtual machine is fine. Docker inside an LXC container is not recommended, and non-Linux hosts are discouraged [1]. If you limit Docker resources, the database needs at least 2 GB of RAM [1].
- How much RAM the ML container eats. It depends on the model you pick. The default search model is
ViT-B-32__openai[12]. In the project's own benchmark (7800X3D, bare metal, no acceleration, full precision) it peaks at about 1,004 MiB of RAM; larger models need roughly 3,000 to 6,600 MiB, for example 3,854 MiB forViT-SO400M-16-SigLIP2-384__webli[10]. The benchmark excludes image decoding and the web server [10]. For the default face modelbuffalo_l[12] we found no memory figure, so we call it unconfirmed. Job concurrency defaults are low (smart search 2, face detection 2, thumbnails 3, video conversion 1) [12], and the docs warn against raising them beyond your CPU cores [13]. - Four ways to handle machine learning. (a) Run it on the same box on the CPU. This is the simplest option. The docs give no throughput numbers, so we make no speed claims. Test with a few hundred photos before you import everything. (b) Switch ML off if you have only 4 GB; you lose content search and face grouping [1]. (c) Move the ML container to a stronger machine. You add its URL in the settings, and if you add it rather than replace the local one, Immich falls back to the local container when the remote is down. The docs warn that image previews travel to that container and that it has no security measures, so keep it on a trusted LAN [9]. (d) Use a GPU. Supported backends are CUDA (NVIDIA, compute capability 5.2 or higher, driver 545 or newer), ROCm (AMD, with a 35 GiB image), OpenVINO (Intel GPUs, with more issues on integrated ones), ARM NN (Mali) and RKNN (Rockchip). The docs call this feature experimental and Linux-only (or Windows through WSL2) [8].
- Video is the second load. By default, videos are transcoded to a compatibility copy; the original stays [6]. The documented defaults are H.264 at 720p, only where needed [12]. Hardware transcoding (NVENC, Quick Sync, RKMPP, VAAPI) is possible, but the docs say it produces significantly larger files with typically lower quality, it is experimental, and the Raspberry Pi is not supported [11].
- Where the disks go. The database folder (
DB_DATA_LOCATION) typically holds 1 to 3 GB and should be on local SSD [1]. The compose file has a switch for databases on hard disks [3]. The media folder (UPLOAD_LOCATION) wants a Unix-compatible filesystem with user and group ownership, such as ext4 or ZFS [1]. Our reading: an SMB share without Unix permissions is a risk for this folder, so test before you commit. On Windows hosts, NTFS is not accepted for the database [1]. - Storage math (our derivation). Thumbnails and transcoded video add about 10 to 20 percent to the library, according to the docs [1]. You can shrink that by lowering the 1440p preview size [13]. Call your original photos and videos L. The server needs about 1.1 to 1.2 times L plus 1 to 3 GB for the database. A local backup copy needs about L, because thumbnails and transcodes can be regenerated [6][7]. An offsite copy needs another L. That makes roughly 3.1 to 3.2 times L, before you count versioned history and growth. The first table after this list shows the numbers. Measure L from your Takeout download or your phone, not from guesses. During the move you need room for the Takeout archives as well. The community tool
immich-go, which the Immich docs recommend for Google Takeout [14], reads ZIP files directly [16]. Its own planning checklist suggests about 1.5 times the source size as free space [15]. That is a third-party rule of thumb. - What a backup must contain. Immich stores file paths and metadata in the database and does not scan the library folder, so database backups are essential [6]. The built-in job writes dumps into
UPLOAD_LOCATION/backups, daily at 02:00 and keeping 14 by default. They contain no photos or videos [6]. The critical originals live inlibrary,uploadandprofile. Thumbnails and encoded video are regenerated by jobs after a restore [6]. The docs state plainly that Immich does not back up the filesystem for you [6], and the project README opens with a 3-2-1 warning [17]. - Backup order. The documentation gives two safe ways. Stop the
immich-servercontainer while you copy, so nothing changes. Or, if that is not possible, copy the database first and the files second. Then the worst case is files the database does not know about. The reverse order can leave you with database entries whose files are missing [6]. The template script from the docs follows this order: it dumps the database into a folder inside the upload location and only then archives everything with Borg, excludingthumbsandencoded-video[7]. We do the same, and the dump is mandatory: the script writes it to/srv/immich/library/database-backup/immich-database.sql.gzbefore Borg starts. That way every archive, local and offsite, contains both the dump and the assets. Both docs pages usepg_dump, so there is no difference between them to work around [6][7]. The script starts withset -euo pipefail. If the dump orgzipfails, the script stops, and no archive is created. Withoutpipefail, a failedpg_dumpcould slip through the pipe and leave a broken file in an archive that looks fine. The template's setup uses--encryption=none[7]. For an offsite copy we would choose an encrypted repository instead and keep its key and passphrase separate from the backup itself; our guide on restic and Borg, listed under Related pages, covers keys. Rehearse the restore either way. - Restore. From the web interface under Administration, Maintenance, you can restore a listed dump; Immich creates a restore point first and rolls back if the restore fails [6]. For a fresh install, the command-line restore needs a database that has never run: delete the database folder if the server has started. The docs mention that the process changed in v2.5.0 [6]. A dump from a different Immich version may need migrations [6].
- What it costs (our calculation, prices from 25 Oct 2026). Google's list prices, quoted on a Telekom shop page, are €2.99 per month for 200 GB and €9.99 per month for 2 TB, which that page sells as Google AI Plus [18]. Over five years that is €179.40 and €599.40. For the offsite copy, Hetzner lists a Storage Box with 1 TB at €3.81 per month including 19 percent VAT (€228.60 over five years) [19] and one with 5 TB at €12.97 per month (€778.20) [20]. Both support Borg and restic [21]. The wattages are our assumptions: a server that draws 10 W around the clock uses 87.6 kWh a year, one at 25 W uses 219 kWh. At 37.0 ct/kWh, the German household average for 2026 so far in BDEW's analysis of August 2026 [23][24], that is €32.41 and €81.03 a year, or €162.06 and €405.15 over five years. Replace the price with your own tariff. Hardware and disks are unconfirmed, because we did not compare models. The second table after this list sums it up. On these numbers, self-hosting with a rented offsite copy does not save money. A cheaper offsite copy, such as a disk at a relative's home, would change that, but we have no price for it. Google's plans also cover Gmail and Drive, and Immich does not replace those. Choose Immich for control, privacy and ownership, and budget for the work. If you also want files and not just photos in your own hands, the Nextcloud guide under Related pages compares self-hosting with renting.
Tables: storage and five-year cost (our derivation)
Disk space by library size, from the factors in steps 8 and 9:
| Library L | Server (1.1–1.2 × L) | All three copies (3.1–3.2 × L) |
|---|---|---|
| 100 GB | 110–120 GB | 310–320 GB |
| 250 GB | 275–300 GB | 775–800 GB |
| 500 GB | 550–600 GB | 1,550–1,600 GB |
| 1,000 GB | 1,100–1,200 GB | 3,100–3,200 GB |
Five-year cost before hardware and disks, from the prices in step 12 (power price 37.0 ct/kWh, the BDEW household average for 2026 so far [23][24]):
| Five years, before hardware and disks | Cloud plan | Self-hosted, 10 W | Self-hosted, 25 W |
|---|---|---|---|
| Library up to about 180 GB (Google 200 GB vs. 1 TB offsite box) | €179.40 | €390.66 | €633.75 |
| Library around 1.5 TB (Google 2 TB vs. 5 TB offsite box) | €599.40 | €940.26 | €1,183.35 |
A homelab example
This is a generic setup for your own server, not a report on ours. We make no statement about Immich or photo hosting in the Bytearium homelab. Assume Linux with Docker, a small SSD at /srv/immich/postgres, a data disk at /srv/immich/library and a backup disk at /mnt/backup.
Download the two files as the docs describe [2]: wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml and wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env. Then edit .env:
UPLOAD_LOCATION=/srv/immich/library
DB_DATA_LOCATION=/srv/immich/postgres
IMMICH_VERSION=v3.3.5
DB_PASSWORD=<random, only A-Za-z0-9>
TZ=Europe/BerlinStart with docker compose up -d and register the first user, who becomes the admin [2]. To test machine learning before the big import, upload a few hundred photos and open the job page.
For the backup, dump the database first with the command from the restore section [6], then copy the files:
#!/usr/bin/env bash
set -euo pipefail
mkdir -p /srv/immich/library/database-backup
docker exec immich_postgres pg_dump --clean --if-exists --dbname=immich --username=postgres | gzip > /srv/immich/library/database-backup/immich-database.sql.gz.tmp
mv /srv/immich/library/database-backup/immich-database.sql.gz.tmp /srv/immich/library/database-backup/immich-database.sql.gz
borg create --stats /mnt/backup/immich-borg::'{now}' /srv/immich/library --exclude /srv/immich/library/thumbs --exclude /srv/immich/library/encoded-videoThe borg create line follows the exclude pattern of the docs' template [7]. Create the repository once with an encrypted mode, for example borg init --encryption=repokey-blake2 /mnt/backup/immich-borg, and keep the key and passphrase separate from the backup. The script writes the dump into /srv/immich/library/database-backup/immich-database.sql.gz first, so every archive contains dump and library together [7]. The offsite copy repeats the borg create against a remote repository, always after the dump has been written, so the offsite archive includes the dump too. On a Hetzner Storage Box, SSH runs on port 23 and you can choose the Borg version with --remote-path, for example borg-1.4 [21]. Because of set -euo pipefail, a failed dump or gzip stops the script before any archive is created.
Rehearse the restore on a second machine: install Immich with the same version in .env, move the backed-up folders into its upload location, and restore the dump with the command-line procedure from the restore section [6]. The web restore accepts .sql.gz files [6], but we did not verify that it accepts a dump made with our command. Check that photos open, not just that the list is there.
Checklist
- Measure your library size in GB from the Takeout archives or the phone, and write down L.
- Check that the host has at least 6 GB of RAM and 2 cores, or decide on ML off or remote ML.
- Pin
IMMICH_VERSIONto a full version, and read the release notes before every upgrade. - Place the database on a local SSD, and keep it off every network share.
- Pick a model deliberately, and compare its memory figure in the docs table with your free RAM.
- Plan about three times L of disk across server, local backup and offsite, and add your growth.
- Back up the database first and the files second, or stop the server container while you copy.
- Exclude
thumbsandencoded-videoonly if you accept regenerating them after a restore. - Encrypt the offsite repository, and store the key apart from the repository.
- Restore on a second machine once, and write down the date and the result.
- Compare costs with your own power price and dated provider prices, not with ours.