Configuration
The Immich URL and user credentials are configured in the app. Infrastructure settings use environment variables or an optional TOML file. Environment variables override matching TOML values.
Set IMMICH_EDIT_CONFIG=/path/to/config.toml to load a file. TOML keys use lowercase names, such as render_max_concurrency for RENDER_MAX_CONCURRENCY.
Settings
| Environment variable | Default | Valid values or purpose |
|---|---|---|
BIND_ADDR | 0.0.0.0:3000 | Listen socket |
DATA_DIR | ./data | Durable database, key, imports, models, and mask rasters; Docker sets /data |
DATABASE_URL | sqlite://DATA_DIR/immich-edit.db?mode=rwc | SQLite connection URL |
PREVIEW_MAX_EDGE | 65535 | 256 to 65535; hard ceiling for preview requests |
RENDER_MAX_CONCURRENCY | Half the CPU cores, clamped to 2 through 4 | Total concurrent renders: previews, exports, AI mask scene renders and edited thumbnails together; must be nonzero |
THUMB_MAX_CONCURRENCY | Quarter of the CPU cores, clamped to 2 through 4 | Background renders (edited thumbnails and batch export jobs), capped one below RENDER_MAX_CONCURRENCY so the editor keeps a slot; with RENDER_MAX_CONCURRENCY=1 background renders share the only slot; must be nonzero |
RAW_FRAME_CACHE_MB | max(RENDER_MAX_CONCURRENCY * 256, 512) | 64 to 16384; decoded preview frames in RAM, subtracted from the host memory budget |
QUALITY_FRAME_CACHE_MB | 512 | 64 to 16384; decoded quality frames in RAM, subtracted from the host memory budget |
GPU_TEXTURE_CACHE_MB | An eighth of the GPU memory budget, 256 to 4096; 512 without a budget | 64 to 16384; reusable GPU textures plus cached white balance, noise reduction, and capture sharpening results |
GPU_MEMORY_BUDGET_MB | Measured from the GPU | 64 or more; GPU memory that server renders share. See GPU memory |
MASK_CACHE_MB | 512 | Disk budget for unreferenced mask rasters; must be nonzero |
EMBEDDING_CACHE_MB | 2048 | Disk budget for click-model embeddings; must be nonzero |
DENOISE_CACHE_MB | 4096 | Disk budget for AI Denoise results; must be nonzero and hold at least one result, up to 6 bytes per pixel. The two most recent results also stay in RAM |
IMMICH_EDIT_RENDERER | auto | auto, gpu, or cpu for the server renderer. A software rasterizer such as llvmpipe is used when no hardware GPU is present, and Diagnostics marks it. Browser previews are chosen per browser under Settings > This device > Preview rendering; see rendering |
GPU_TIMESTAMPS | false | true records device time per GPU render stage in Diagnostics. Needs an adapter with timestamp queries; others fall back to wall time only |
ML_RUNTIME | auto | auto, gpu, cpu, or off |
ML_MAX_EDGE | 2048 | 256 to 8192; source edge sent to mask inference |
ML_MAX_CONCURRENCY | 1 | Concurrent inference jobs for AI masks and AI Denoise; must be nonzero |
ML_IDLE_SECS | 60 | Seconds before an inactive model session unloads |
ALLOWED_ORIGINS | Empty | Comma-separated HTTP or HTTPS origins without a path or trailing slash |
TRUSTED_PROXIES | Loopback, private, and link-local ranges | Comma-separated IP addresses or CIDR prefixes whose X-Forwarded-For and X-Forwarded-Proto headers are believed |
MAX_BODY_MB | 128 | Maximum request body size; must be nonzero |
REQUEST_TIMEOUT_SECS | 60 | Timeout for ordinary API requests; must be nonzero. Export requests use ORIGINAL_TIMEOUT_SECS plus EXPORT_TIMEOUT_SECS instead |
ORIGINAL_TIMEOUT_SECS | 120 | Immich original-download timeout |
EXPORT_TIMEOUT_SECS | 300 | Immich export/upload timeout |
CF_ACCESS_CLIENT_ID | Empty | Cloudflare Access service token ID sent to Immich; see Cloudflare Access |
CF_ACCESS_CLIENT_SECRET | Empty | Cloudflare Access service token secret; set together with CF_ACCESS_CLIENT_ID |
Environment-only paths
These settings do not have TOML equivalents:
| Variable | Native default | Docker value | Purpose |
|---|---|---|---|
WEB_DIR | ./web | /app/web | Built static frontend |
DCP_DIR | ./assets/dcp | /app/assets/dcp | Bundled camera profiles imported at startup |
IMMICH_EDIT_CONFIG | None | None | TOML configuration path |
RUST_LOG | info | info | Log filter; see logs |
LOG_FORMAT | pretty | pretty | pretty for readable lines, json for one JSON object per line |
Logs
Every API response writes one line on the http target. It carries the request ID, method, path without the query string, user, status and latency. Error responses add the error code and the message sent to the client, including why a malformed request body was rejected. Server errors (5xx) log at error. 400, 408, 409, 413, 422 and 429 log at warn. Other 4xx responses log at info, except 401 and 404, which log at debug with successful responses.
A session cookie the server cannot read, for example after instance.key changes, logs an error and the request continues as signed out.
Other targets:
| Target | Content |
|---|---|
upstream | Failed Immich calls with their cause |
client | Browser errors from signed-in sessions, at most 30 a minute per user |
panic | Panics with location and backtrace |
onnxruntime | ONNX Runtime messages from AI models. Warnings and errors by default; debug adds session setup and per-run detail |
The application itself logs under immich_edit_backend. For example, RUST_LOG=info,http=debug adds successful requests.
Example TOML
bind_addr = "127.0.0.1:3000"
data_dir = "/srv/immich-edit"
renderer = "auto"
ml_runtime = "auto"
render_max_concurrency = 2
allowed_origins = ["https://edit.example.com"]
trusted_proxies = ["10.0.0.0/8", "2001:db8::/32"]
Trusted proxies
The client IP used for login rate limiting, and the Secure flag on the session cookie, come from X-Forwarded-For and X-Forwarded-Proto. Those headers are only believed when the connecting peer is listed in TRUSTED_PROXIES, because any client can send them.
The default list is 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, ::1/128, fc00::/7, and fe80::/10, which covers a reverse proxy on the same host or the same Docker network. Set the variable when your proxy connects from a public address:
TRUSTED_PROXIES=203.0.113.7,2001:db8::/32
Setting the variable replaces the defaults rather than extending them, so include the private ranges you still need. An entry without a prefix length is a single host. To trust nothing, set trusted_proxies = [] in the TOML file; every request then uses the peer address and no session cookie is marked Secure.
Startup logs a warning when the server binds a specific public address and no trusted prefix is outside the private ranges, because that combination silently collapses every client to the proxy address.
Cloudflare Access
When Immich sits behind Cloudflare Access (Zero Trust) and immich-edit cannot reach it on a private network, Access answers every server-side Immich call with a redirect to its login page. Setup then fails with upstream status 302.
Create a service token under Access > Service credentials > Service Tokens. Then add a policy to the Immich application with the action Service Auth that includes that token. Give immich-edit the token:
CF_ACCESS_CLIENT_ID=<id>.access
CF_ACCESS_CLIENT_SECRET=<secret>
Every request from immich-edit to Immich then carries the CF-Access-Client-Id and CF-Access-Client-Secret headers. Browser sign-in through Immich OAuth still goes through your normal Access login.
Removed settings
v0.4.0 refuses to start when a removed key is present. The error names the replacement.
| Removed | Replacement |
|---|---|
CACHE_DIR | DATA_DIR |
SEGMENT_RUNTIME | ML_RUNTIME |
SEGMENT_MAX_EDGE | ML_MAX_EDGE |
SEGMENT_MAX_CONCURRENCY | ML_MAX_CONCURRENCY |
SEGMENT_IDLE_SECS | ML_IDLE_SECS |
IMMICH_URL, IMMICH_API_KEY, AUTH_TOKEN, and IMMICH_EDIT_INSECURE are also no longer read. Configure the Immich connection through first-run setup.