Skip to content

Latest commit

 

History

History
253 lines (166 loc) · 17.1 KB

usage.md

File metadata and controls

253 lines (166 loc) · 17.1 KB

Using the accelerator

Day-to-day operation once you're set up — see the quick start if you haven't installed yet.

Commands

Every command is prefixed with immich-accelerator (e.g. immich-accelerator setup).

Command What it does
setup Auto-detect local Docker, extract server, configure
setup --url URL Set up from a remote Immich instance
setup --manual Create a config template for manual editing
setup --ml-only Set up this Mac as an ML-only network compute node
start Run worker + ML once in the foreground (testing only; use the service for auto-restart/update/log-rotation)
stop Stop native services
status Show what's running
logs [worker|ml] Tail service logs
update Update to match a new Immich version
watch Monitor + auto-restart/update + log rotation (what the service runs)
dashboard Web UI at http://localhost:8420
component [name] [on|off] Turn the worker, ML, or dashboard on or off (no args lists them)
ml-test Diagnose the ML service (health + CLIP + OCR round-trip)
selftest Run every kind of work (thumbnails, HEIC, metadata, video, backups, ML) through Immich's own code on sample files; runs on its own whenever Immich or the accelerator changes version
encoding Show the hardware transcoding switches, or set one: encoding hardware-video off (see below)
encoding preset [software|hardware] Move every switch to one end at once
compare <video> Encode one of your own files every way this Mac can and open a page with the numbers and a frame from each
encode-compare <video> The same comparison as text, and the VideoToolbox quality closest to what Immich produces on its own
uninstall Remove services, data, and launchd config

If a command isn't behaving as documented here, see troubleshooting.md.

Running as a service (recommended)

Run the accelerator as a background service, not with a bare immich-accelerator start. The service runs watch mode, and only watch mode gives you:

  • Auto-restart: launchd (KeepAlive) restarts the monitor if it dies; the monitor restarts the worker, ML, and dashboard if they crash.
  • Auto-update: picks up new Immich versions (re-extracts the worker) and notifies on accelerator updates — see Updates below.
  • Log rotation: caps worker.log/ml.log so they can't grow without bound.

A plain immich-accelerator start runs once in the foreground with none of the above. Use it only for quick testing.

Homebrew install (recommended):

brew services start epheterson/immich-accelerator/immich-accelerator

This uses the formula's own service definition, survives brew upgrade, and restarts at login. Check it with brew services list. Stop with brew services stop epheterson/immich-accelerator/immich-accelerator.

Don't also install the launchd plist below if you're using brew services. Running both double-starts the watcher.

Git / non-Homebrew install: immich-accelerator setup offers to install a launchd LaunchAgent (~/Library/LaunchAgents/com.immich.accelerator.plist). If you skipped that prompt, re-run setup and it will offer again.

Either way the service uses watch mode with KeepAlive. Confirm everything is healthy with immich-accelerator status and immich-accelerator ml-test.

Updates

The accelerator handles Immich updates automatically:

  • On every start: an all-in-one install checks the version of the container on this Mac and re-extracts if it changed. A split install does not check here; its version check is the watcher's, below.
  • In watch mode: checks every 5 minutes. If Watchtower or a manual docker compose pull updates Immich, the watchdog stops the worker, re-extracts the new server, and restarts. No manual intervention needed.
  • Manual: immich-accelerator update if you prefer to control the timing

A split install takes the version from the Immich you configured with setup --url, never from a container on the Mac, and so needs an api_key in its config for any of this to run.

To update the accelerator itself:

brew upgrade immich-accelerator

If you run it as a service (watch mode, the recommended setup above), that's all you need: within ~30s the watcher notices the new version on disk, relaunches itself, and restarts the worker and ML service on the new code. (A detached worker survives a plain restart, so this version-aware reload is what guarantees the new code actually takes effect; brew services restart alone wouldn't reload the worker.)

If you run the worker manually instead of as a service, restart it yourself after upgrading:

immich-accelerator stop && immich-accelerator start

If brew upgrade says there's nothing to do but you know a newer release exists, see Troubleshooting.

Dashboard and menu bar app

Dashboard

Real-time monitoring at http://your-mac:8420:

immich-accelerator dashboard

Shows service health, processing progress with live rates and ETAs, Apple Silicon hardware utilization, and system metrics. Mobile-friendly, check from your phone.

The dashboard and setup use the Immich API for job status and queue control. Create an API key from an admin account in Administration > API Keys with these permissions:

Permission Used by Why
job.read Dashboard Show queue activity (active/waiting counts)
job.create Dashboard Re-queue button
asset.read Setup Detect upload library path
library.read Setup Detect external library paths

All job.* and library.* endpoints require admin access. If the dashboard shows "API key invalid," make sure the key was created by an admin user.

Dashboard

The dashboard binds 0.0.0.0:8420 (LAN-accessible) by default — see security.md before exposing it beyond a trusted network.

Menu bar app

A native menu-bar app shows accelerator health at a glance and covers the daily actions: worker / ML / dashboard status (with a NATIVE or PYTHON engine badge), start / stop / restart, run ml-test inline, open Immich, the dashboard, or logs, and launch-at-login. It reads the accelerator's own state directly (no extra services) and weighs about 90KB.

brew install --cask epheterson/immich-accelerator/immich-accelerator-menubar
open "/Applications/Immich Accelerator.app"

Design inspired by Immich-Accelerator-Helper by @pl4za.

Choosing what runs

The accelerator is three separate processes, and each one can be turned off independently:

Component What it does Turn it off when
worker Thumbnails, video transcoding, metadata, RAW/HEIC decode Another machine already runs the worker and you only want this Mac for ML
ml Smart search (CLIP), face detection, OCR Another machine already does ML and you want this Mac for thumbnails and VideoToolbox
dashboard The web UI on port 8420 You use the menu bar app, or you don't want a port open
immich-accelerator component              # list what's on
immich-accelerator component ml off       # this Mac does thumbnails and video, not ML
immich-accelerator component worker off   # this Mac does ML only

Changes apply immediately, including to a running service, and they persist as plain keys in ~/.immich-accelerator/config.json. The menu bar app's Settings window has the same three switches, and a component you turn off disappears from the menu rather than showing as a red failure.

Turning ml off hands ML to another machine, so tell it where. The accelerator normally points the worker at its own engine on localhost. With ml off it stops setting that, and whatever you configured in Immich under Administration → Machine Learning Settings applies instead. Immich's default there is immich-machine-learning:3003, a Docker-internal hostname a worker running natively on macOS cannot resolve, so if you never changed it every ML job will fail. Either set that URL in Immich to a reachable engine, or set "ml_url" in config.json to name it here. Toggling ml restarts the worker, because that URL is fixed when the worker starts.

This goes as far as the process boundaries and no further. Video, thumbnails, metadata and RAW decode all happen inside the single Immich microservices worker, so "video but not thumbnails" isn't something the accelerator can offer. That split is Immich's job scheduler: use Administration → Jobs to pause individual queues, and see Performance tuning below for concurrency.

worker off, ml on is common enough to have its own setup flag — see ML-only network node.

Performance tuning

In the Immich admin UI (Administration → Jobs), tune the per-queue concurrency for your hardware. Recommended for M4 with 24GB:

Queue Concurrency Why
Thumbnail Generation 4 CPU-bound (Sharp/libvips with NEON SIMD)
Smart Search 2 GPU-serialized (MLX Metal, no benefit higher) for the default and SigLIP models
Face Detection 3 Neural Engine (Vision framework)
OCR 3 Neural Engine (Vision framework)
Metadata Extraction 4 I/O-bound (exiftool)
Video Conversion 1 Hardware-accelerated via VideoToolbox

Higher isn't always better. Oversubscribing the CPU causes thrashing and actually reduces throughput.

The ONNX models in the CLIP zoo (anything that isn't the default MLX model) let onnxruntime use every core, which is right on a Mac doing nothing else and less obviously right while the worker is transcoding on the same machine. IMMICH_ACCEL_ML_THREADS caps it without touching the worker; unset means "use every core", which stays the default.

The cap is close to free, because the parallelism saturates early. On an M4 with ViT-B-16, capping to 2 measured 179ms against 175ms uncapped, for 8 fewer threads competing with the worker. Try it if search feels like it's making the rest of the machine sluggish.

Configuration details

Setting IMMICH_ACCEL* variables

Put them in the env block of ~/.immich-accelerator/config.json:

{
  "env": {
    "IMMICH_ACCELERATOR_HEIC_DECODE_CONCURRENCY": "2",
    "IMMICH_ACCEL_ML_THREADS": "4"
  }
}

They are passed to the worker and the ML service, and the accelerator reads its own from there too. Restart with brew services restart immich-accelerator to apply.

A real environment variable still wins, so running the accelerator by hand with one exported does what you would expect. The config block exists because the environment cannot be reached on a Homebrew install, not to outrank it.

Setting them in the shell environment does not work on a Homebrew install, which is why this exists: brew services generates the launch agent, it carries no environment, launchctl setenv does not reach it, and editing the plist is undone the next time the service restarts.

Only IMMICH_ACCEL* names are accepted. Everything else a service needs is worked out at startup, and anything else in that block is ignored with a warning.

Hardware transcoding

Three switches decide how much of transcoding runs on the video hardware rather than on the CPU. Settings shows them under Hardware Transcoding; the CLI sets the same values.

Switch Variable Default What it does
Decoding IMMICH_ACCEL_HW_DECODE on Decodes video, thumbnails and previews with VideoToolbox
Video Encoding IMMICH_ACCEL_HW_VIDEO on Encodes H.264 and HEVC with VideoToolbox
Audio Encoding IMMICH_ACCEL_HW_AUDIO on for new installs, off for upgrades Encodes AAC with AudioToolbox (aac_at)

Set one at a time:

immich-accelerator encoding                      # show all three
immich-accelerator encoding hardware-video off

Or move all three at once. Software turns everything off, which is exactly what Immich's own container does, so video and thumbnails come out byte for byte what Docker produces. Hardware turns everything on:

immich-accelerator encoding preset software
immich-accelerator encoding preset hardware

Any other combination is a valid place to be, and both Settings and the CLI call it Custom.

One exception, in either position: if ffmpeg cannot decode a file at all, the wrapper falls back to QuickLook for that one thumbnail, so it did not come from ffmpeg and Docker on the same file would either produce a different thumbnail or fail outright. Nothing turns that off, because the alternative is no thumbnail. It is reached only when ffmpeg rejects the stream outright, which in practice means some HDR10 phone footage.

Audio is the one switch that is off for anyone upgrading. aac_at is faster and uses about a third less CPU, but the bytes differ from Docker's, so an existing install is never moved onto it without being asked. A new install starts at Hardware.

What the hardware actually buys you

"Hardware" does not simply mean "faster". Immich asks ffmpeg for preset ultrafast, which is genuinely quick, so on an idle Mac the software encoder often finishes a single file sooner. What VideoToolbox buys is the rest of the machine. Measured on an M4 over 20 seconds of 1080p camera footage: software finished in 1.5 seconds but spent 12.5 seconds of CPU across about eight cores, while VideoToolbox took 2.8 seconds of wall clock and 5 seconds of CPU across about two. On a Mac also running Immich's other jobs and the machine learning engine, that is usually the trade you want.

Whether hardware also wins on quality depends on which software encode you compare it with. Against Immich's default, preset ultrafast, it wins outright, because ultrafast disables most of what x264 is good at. On a 23-second 1080p phone clip, VideoToolbox produced 7.6 MB at SSIM 0.957 where software produced 19.9 MB at 0.952, for about half the CPU. Against x264 at veryfast it no longer does: the same clip came out at 7.3 MB and SSIM 0.958 in software, slightly smaller and slightly better, for three times the CPU.

@RxChi1d measured this properly, 99 encodes across six real clips scored with MS-SSIM and LPIPS against a lossless reference, and found that at equal quality veryfast needs 2.1 to 4.8 times fewer bytes than VideoToolbox, at 7 to 13 times the CPU (#162). The data and scripts are attached there.

So VideoToolbox trades storage for CPU. On a Mac that is also running Immich's other jobs and the machine learning engine, CPU is usually the scarce resource and that is the right trade. If storage matters more to you than CPU, Software with Immich set to veryfast makes smaller files for the same quality. Either way these numbers vary with the footage, which is what the comparison commands below are for.

preset ultrafast is also the assumption both comparison commands make about your software side, because it is what Immich ships. If you have configured Immich for a different x264 preset, tell them so, or the comparison is against something you do not run:

immich-accelerator compare ~/Movies/clip.mov --preset veryfast

That one matters more than it sounds. On the 20 seconds of camera footage measured above, ultrafast produced 66.6 MB at SSIM 0.967 while veryfast produced 33.2 MB at 0.972: half the bytes at higher quality, from the same encoder. Which end of the comparison you are standing on changes the answer.

compare writes a page with a frame from each encode next to the measurements, since a table cannot tell you whether you would notice the difference. encode-compare prints the same measurements as text.

Understanding IMMICH_MEDIA_LOCATION

This is the directory Immich uses as its media root. It contains these subdirectories: upload/, thumbs/, encoded-video/, library/, profile/, backups/. Both Docker and the native worker must see this directory at the same absolute path. Setup handles this automatically for same-machine installs.

Putting thumbnails or transcodes on a faster disk

Immich derives every storage path from IMMICH_MEDIA_LOCATION, so there is no separate setting for thumbnails (this is true in Docker too). To keep the library on slow storage while thumbnails live on an SSD, symlink the subdirectory:

immich-accelerator stop
mv /path/to/media/thumbs /Volumes/fast-ssd/thumbs
ln -s /Volumes/fast-ssd/thumbs /path/to/media/thumbs

The same works for encoded-video/. Immich follows the symlink, so reads and writes land on the SSD.

If the SSD is not mounted, that symlink points nowhere and every job writing to it would fail. The accelerator checks for this at startup and refuses to start, naming the broken path, instead of letting those jobs fail one by one.