What Memory Limit Should You Set for Immich?

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

Do not set one Immich memory limit from a universal GB number. A host-level RAM target and a per-container cap solve different problems: the host must support the whole stack, while a container limit should protect the host without killing a legitimate Immich workload.

Browsing a processed library can look light while a cold machine-learning start, a large import, thumbnail generation, face analysis, or video work consumes much more memory. Measure the heaviest workload you actually need, keep headroom for PostgreSQL and the operating system, and treat repeated OOM kills as a failed limit rather than normal throttling.

Measure Memory Pressure Before Choosing the Limit

Record memory during three states: quiet browsing, a representative daily upload, and the heaviest planned background workload. Capture container usage, host available memory, swap activity, OOM events, and whether jobs continue to make progress. A single peak from docker stats is not enough because Linux memory accounting includes several kinds of memory with different reclaim behavior.

A useful Docker cgroup memory breakdown separates anonymous memory, file-backed cache, and slab instead of treating the raw total as equally dangerous. Stable file cache with healthy host headroom is different from steadily rising anonymous memory, swap pressure, or a cgroup OOM counter that increases during the same Immich job.

Pass this stage when you can identify a repeatable high-water mark and explain whether it is mostly reclaimable cache or active working memory. If usage keeps climbing across an unchanged workload, a container is repeatedly OOM-killed, or the host begins swapping heavily, stop sizing from that run and diagnose the abnormal growth first.

Size the Cap Around the Heaviest Valid Immich Workload

Choose the workload that must remain supported after the limit is applied. For one household that may be four phones uploading while Smart Search and face jobs catch up; for another it may be a large initial import followed by normal browsing. Keep the dataset, model, concurrency settings, and other containers fixed while measuring so the limit reflects a defined service promise.

Place the hard cap above the observed non-reclaimable peak with enough measurable margin for short bursts, while preserving host memory for PostgreSQL, filesystem cache, the container runtime, and unrelated services. The related ZimaSpace checklist for local-AI resource warning signs is useful because heat, swapping, and sudden restarts reveal host-level stress that an Immich-only graph can miss. Do not interpret “the container touched the limit once” as proof that more RAM is required. The important failure boundary is whether the same valid workload slows severely, loses jobs, swaps continuously, or is OOM-killed. Conversely, a limit is too loose if Immich can starve the database or the host before its own cgroup becomes the boundary.

Reduce the Workload Before Raising a Limit for Abnormal Growth

If the proposed cap fails only during one class of background work, reduce that job's concurrency or isolate the stage before raising the ceiling. Machine learning, thumbnail generation, video processing, and database work can have different memory profiles. A smaller active batch may finish more slowly while keeping the household interface responsive and the host recoverable.

Version-specific failures also matter. An Immich v3.0.3 memory report described a machine-learning worker growing until a cgroup limit triggered OOM after a malformed locale-related condition. That case does not define normal Immich RAM use; it demonstrates why unexplained growth should be treated as a software or configuration branch before permanently increasing the host budget.

After changing one concurrency, model, or version variable, rerun the same workload. Keep the change only if both the memory signature and the original job improve in the expected direction. If memory still rises without approaching a stable plateau, preserve logs and version details and escalate rather than turning the hard limit into an ever-larger number.

Validate the Limit After a Cold Restart and a Busy Cycle

Restart the host so caches and model residency begin from a known cold state. Run the normal login and browsing checks, then the representative upload and background workload. Record peak anonymous memory, cache, swap, OOM counters, database response, queue drain time, and whether another important container remains responsive.

A passing limit survives both cold start and the busiest normal cycle without OOM kills, sustained swap thrashing, repeated container restarts, or a queue that stops draining. It should also leave enough host headroom for recovery tasks such as a database dump or administrative login when Immich is busy.

If only an artificial stress test fails while every defined household workload passes, document the accepted boundary instead of buying RAM for a scenario you do not need.

If a real workload cannot pass without exhausting the host, lower concurrency, isolate machine learning, add memory, or move competing services; then repeat the same validation before declaring the new limit safe.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.