Takeout returns five to twenty zips capped at 50GB each, ready within 24 hours. Unzip them to staging, then run immich-go upload against http://localhost:2283 with –google-photos and –create-albums so the .json sidecars restore dates, locations and albums. Indexing 80,000 photos takes 8-12 hours on CPU, 2-4 with CUDA.
By LK Wood IV · 2026-06-11 · ~14 min read · St. Louis County, MO
Immich is the only self-hosted photo library that’s actually replaced Google Photos for most users in 2026 — face recognition, CLIP semantic search (“photos of the lake”), the timeline view, and a mobile backup app that runs automatically in the background. This guide sets up Immich from scratch and migrates an existing Google Photos library using the Takeout export path.
For the Immich vs PhotoPrism vs Ente comparison, see the self-hosted photo library showdown.
Hardware requirements
| Scenario | RAM | CPU | GPU |
|---|---|---|---|
| Small library (<20K photos), no active ML | 4GB | 2 cores | Not needed |
| Typical library (20–100K photos) | 8–16GB | 4 cores | Helpful but not required |
| Large library (100K+ photos), fast initial index | 16–32GB | 6–8 cores | CUDA GPU recommended for indexing speed |
| Running alongside other services | Add 4–8GB buffer |
ML indexing speed matters most during the initial import. On a library of 80,000 photos:
- CPU-only indexing: ~8–12 hours
- Intel Quick Sync (VAAPI): ~4–6 hours
- NVIDIA GPU (CUDA): ~2–4 hours
After initial indexing, ongoing ML processing (new photos) runs in minutes.
Step 1: Deploy Immich with Docker Compose
Create the Immich stack directory:
mkdir -p /opt/stacks/immich && cd /opt/stacks/immich
Download the official Docker Compose files:
wget -O docker-compose.yml \
https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env \
https://github.com/immich-app/immich/releases/latest/download/example.env
Edit .env:
nano .env
Set these values:
# Upload path — where your photos will be stored
# Point this at your NAS mount or a large volume
UPLOAD_LOCATION=/mnt/photos/immich
# Database credentials (generate strong passwords)
DB_PASSWORD=your-strong-db-password-here
# Timezone
TZ=America/Chicago
Create the upload directory:
mkdir -p /mnt/photos/immich
Pin the Immich version — the :release tag in the official compose file is a moving target. Pin to a specific version to avoid surprise schema migrations:
# Find the latest stable release
IMMICH_VERSION=$(curl -s https://api.github.com/repos/immich-app/immich/releases/latest | grep '"tag_name"' | cut -d '"' -f 4)
echo "IMMICH_VERSION=$IMMICH_VERSION" >> .env
Start Immich:
docker compose up -d
Immich starts several containers: immich-server, immich-microservices, immich-machine-learning, redis, and database. The initial startup takes 2–3 minutes while the database initializes.
Access the web UI at http://your-host-ip:2283. Create the admin account on first launch.
Step 2: Configure storage and external libraries
In Immich Settings → Storage:
The default storage structure stores originals in UPLOAD_LOCATION/{userID}/{year}/{month}/. If you prefer to preserve the original directory layout from your existing photo archive, configure an External Library instead:
Administration → External Libraries → Create Library:
- Point it at an existing folder (e.g.,
/mnt/photos/archive) that Immich mounts read-only - Immich indexes and searches photos in this location without copying or modifying them
- Use this path for existing photo archives you want to browse in Immich but manage outside of it
For Google Takeout imports and new phone backups, let Immich manage the storage via the Upload path.
Step 3: Mobile backup setup
Immich mobile app is available on iOS and Android (search “Immich” in the App Store / Play Store).
After installing:
- Open the app → enter your server URL:
http://192.168.1.10:2283(or your NPM domain if you’ve set that up) - Log in with your account
- Tap the profile icon → Backup → configure backup on WiFi only or on any network
- Enable “Background Backup” in the app settings
For background backup to work reliably on iOS:
- Go to iOS Settings → Immich → allow background app refresh
- On iOS, the Immich app must be opened periodically to trigger background sync (iOS background task limitation)
For full automatic background backup on Android, enable the “Ignore Battery Optimization” option in the app.
Step 4: Enable hardware ML acceleration
Hardware acceleration dramatically reduces the time to index your library. Configure it based on your hardware.
NVIDIA GPU (CUDA):
In docker-compose.yml, under immich-machine-learning:
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
The NVIDIA Container Toolkit must be installed on the host:
# On Proxmox or Docker host
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt update && apt install -y nvidia-container-toolkit
systemctl restart docker
Intel Quick Sync (VAAPI) / OpenVINO:
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-openvino
devices:
- /dev/dri:/dev/dri
After changing the image and adding device access, redeploy:
docker compose pull
docker compose up -d
In the Immich web UI → Administration → Jobs → Machine Learning: confirm the GPU is being used (processing speed should increase noticeably).
Step 5: Migrate Google Photos via Takeout
Request your Takeout export:
- Go to takeout.google.com
- Deselect everything, then select “Google Photos” only
- Choose “Export once”, maximum file size (50GB per archive),
.zipformat - Google emails you when the export is ready (30 min to 24 hours)
Download all the zip files to your server. With a large library, expect 5–20 zips. At up to 50 GB per archive that is a serious one-time download, so if your ISP enforces a monthly cap, check it against your normal usage with the data usage calculator before you kick it off.
Install immich-go, the tool that handles Takeout import correctly (preserving metadata from .json sidecars):
# Get the latest release from GitHub
IMMICH_GO_VERSION=$(curl -s https://api.github.com/repos/simulot/immich-go/releases/latest | grep '"tag_name"' | cut -d '"' -f 4)
# Pick the build for your architecture. Most homelab hosts are x86_64;
# use immich-go_Linux_arm64.tar.gz on a Pi or other ARM box.
ARCH_FILE=immich-go_Linux_x86_64.tar.gz
wget "https://github.com/simulot/immich-go/releases/download/${IMMICH_GO_VERSION}/${ARCH_FILE}"
tar xzf "${ARCH_FILE}"
mv immich-go /usr/local/bin/
Get your Immich API key: Immich web UI → Profile → API Keys → New API Key.
Run the import:
# Extract all Takeout zips to a staging directory
mkdir -p /mnt/staging/takeout
for f in /mnt/staging/takeout-zips/*.zip; do
unzip -q "$f" -d /mnt/staging/takeout
done
# Import with immich-go
immich-go upload \
--server http://localhost:2283 \
--api-key YOUR-API-KEY \
--google-photos \
--create-albums \
/mnt/staging/takeout/Takeout/Google\ Photos/
The --google-photos flag tells immich-go to look for .json sidecar files and apply their metadata. The --create-albums flag recreates your Google Photos albums in Immich.
Expect 30–90 seconds of processing per 1,000 photos for a CPU-based ML setup. Watch progress with immich-go output — it reports files processed, skipped (duplicates), and any errors.
Handle duplicates: If you’ve already imported some photos via mobile backup before running Takeout, immich-go detects duplicates by file hash and skips them. You won’t get duplicates in your library.
After import completes, let Immich run ML indexing on the new photos. In the web UI → Administration → Jobs → Face Detection: queue this job to run. It can take hours on a large library.
Step 6: Reverse proxy with Nginx Proxy Manager
Get your Immich accessible at a clean URL instead of 192.168.1.10:2283:
In Nginx Proxy Manager → Add Proxy Host:
- Domain:
photos.yourdomain.com - Scheme:
http - Forward to:
immich-servercontainer name (or LAN IP if separate host) - Port:
2283 - SSL: enable with your wildcard cert
- Client max body size: Set in the Advanced tab:
client_max_body_size 0;— required for large file uploads from mobile
Update the mobile app: replace the server URL with https://photos.yourdomain.com.
Step 7: Backup strategy
Immich’s official backup documentation is thorough. The short version:
What to back up:
UPLOAD_LOCATION— all your original photos and videos- PostgreSQL database — ML embeddings, face clusters, album structure, metadata
PostgreSQL backup:
docker exec -t immich_postgres pg_dumpall -c -U postgres > \
/mnt/backups/immich/db-$(date +%Y%m%d).sql
Automate this with a cron job:
echo "0 3 * * * root docker exec -t immich_postgres pg_dumpall -c -U postgres > /mnt/backups/immich/db-\$(date +\%Y\%m\%d).sql" >> /etc/crontab
Photo backup via restic:
If you’re running restic for off-site backups, add UPLOAD_LOCATION and your database dump directory to the backup paths. Photos are the highest-priority backup target — originals are only in one place.
A common mistake: backing up only the Docker volumes (which contain thumbnails and cache) instead of UPLOAD_LOCATION. Back up the actual photo directory.
Common issues
ML indexing not starting: Check that immich-machine-learning container is running: docker compose ps. If it’s restart-looping, check logs: docker compose logs immich-machine-learning. CUDA issues usually show as “CUDA not available” — verify the NVIDIA Container Toolkit is installed and the container has GPU access.
Google Takeout import skipping files: immich-go skips files it has already imported (by hash). Run with --dry-run first to see what would be imported without committing.
Mobile app can’t connect: Verify the server URL includes the port if you’re using the direct IP (http://192.168.1.10:2283). If using NPM, verify the client_max_body_size 0 setting is in the advanced config and that the SSL cert is valid.
Thumbnails not generating: Jobs in Immich run asynchronously. After a large import, the thumbnail and ML jobs queue behind each other. Check Administration → Jobs — each job type shows queued/active/failed counts. Failed jobs usually indicate a storage permission issue on UPLOAD_LOCATION.
Comparing Immich to PhotoPrism and Ente before committing? The self-hosted photo library showdown covers all three. For access from anywhere, Tailscale or WireGuard give your mobile app a direct path to Immich without exposing the server publicly.
Sources
- Immich Docker Compose install – official docs on the recommended compose deployment, .env config, and container set.
- Immich Backup and Restore – official docs on backing up the upload location and PostgreSQL database.
- immich-go – official repository for the tool that imports Google Photos Takeout and preserves JSON sidecar metadata.
- Installing the NVIDIA Container Toolkit – official guide for the host toolkit required for CUDA machine-learning acceleration.
Frequently asked questions
How long does Google Takeout take to process?
Does Immich import all Google Photos metadata (location, date, albums)?
How much RAM does Immich need?
Can I keep my original photos without Immich modifying them?
What happens to the Google Photos metadata that doesn't match a file?
Evidence ledger
- Last updated
- Methodology
- This tutorial was written and edited by Lowell K. Wood IV in St. Louis County, MO. Specs, prices, commands, and version numbers are drawn from the official vendor, reseller, and project documentation current on the date above, and were verified before publishing. First-person hardware claims appear only where the article shows a verifiable artifact — a photo, receipt, or measurement — or links to the TechFuelHQ Open Bench Datasets. Every fact is human-verified against its cited source before publishing; AI assists with first-draft structure and source-gathering, not with the verdict. Full editorial standard: methodology.
- Update log
- 2026-07-25 — Last reviewed and updated.
- Corrections
- Spotted an error or stale price? Email hello@techfuelhq.com. Confirmed corrections are added to the update log above.