axonasif/immich-nix

Runs Immich natively on macOS (Apple Silicon) and Linux. No Docker, no VM. Nix based, with CoreML GPU hardware acceleration on macOS.

0

stars

43

commits

Shell

primary language

Sep 8, 2026

updated

README

immich-nix for macOS and Linux

Immich built and run natively with Nix, without Docker. Apple Silicon macOS and aarch64/x86_64 Linux are supported. GPU-accelerated machine learning is available on Apple Silicon through CoreML.

This project provides a low-complexity, single-host deployment designed for macOS and Linux. Nix supplies the build toolchain, native libraries, PostgreSQL, and Valkey, while Immich is built from its pinned upstream source with its own pnpm and uv workflows. Application data, runtime state, and build outputs remain inside the repository by default.

This is an independent deployment method, not an official Immich distribution. Upstream recommends Docker Compose for production installations.

CleanShot 2026-09-04 UTC 02 48 20@2x

Design

Packaging Immich as a conventional Nix derivation would require maintaining pnpmDeps hashes and a separate Python package set. It also encounters two Darwin-specific limitations: nixpkgs marks extism-js-core as broken on Darwin, and its ONNX Runtime build does not include the CoreML execution provider. Building with upstream's package managers avoids both constraints, at the cost of network-dependent, non-hermetic builds.

On Apple Silicon, the local machine-learning patch selects a working execution route for each model family. In testing on an M1 Pro, smart-search indexing reached 32–37 images per second with CoreML with the immich-app/ViT-SO400M-16-SigLIP2-384__webli model, compared with 3-10 images per second on CPU. With the smaller ViT-B-16-SigLIP2__webli model, you can get ~120 images per second on M1 Pro. The patch also avoids an ONNX Runtime issue that can expand the SO400M text model into a 6.5 GB CoreML program. See UPGRADING.md for the implementation rationale and measurements.

Requirements

  • Nix with flakes enabled
  • Apple Silicon macOS, or aarch64/x86_64 Linux

macOS does not require Homebrew or Xcode. System installations of Node.js and Python are not required on either platform. Your system is not polluted.

Installing Nix

For macOS, use the official multi-user installer:

curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh
Linux installation

For Linux systems using systemd with SELinux disabled, use the recommended multi-user installation:

curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh -s -- --daemon

After installation, start a new shell and enable the Nix command interface and flakes with the following commands:

mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf

See the official Nix download and installation instructions for other configurations, single-user installation, and troubleshooting.

Installation

The repository contains pinned Immich and base-images submodules and must be cloned recursively:

git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/axonasif/immich-nix.git
cd immich-nix

Build the complete stack once:

nix develop --command scripts/build.sh

Then start Immich:

nix develop --command scripts/immich.sh start

The web application is then available at http://0.0.0.0:2283. The initial build downloads the nixpkgs closure and application dependencies, then compiles sharp against the Nix-provided libvips. Subsequent builds reuse downloaded dependencies and are substantially faster.

By default, the assembled application is stored in .local/immich-app, while PostgreSQL, Valkey, logs, cached models, and media are stored in .local/immich-run. No files are installed system-wide. Consequently, removing the checkout also removes all data stored in these default locations.

Operation

Run nix develop to enter the immich env shell first to use the commands below easily.

scripts/immich.sh status
scripts/immich.sh logs
scripts/immich.sh stop
scripts/immich.sh restart

The upstream CLI and administration tool are included in the build:

export PATH="$PWD/.local/immich-app/bin:$PATH"
immich --help
immich-admin --help

Data locations and configuration

The default paths isolate a fresh checkout from any existing Immich installation. To use an existing PostgreSQL cluster or media library, define the relevant paths before starting the stack:

export IMMICH_PGDATA=/path/to/postgres
export IMMICH_MEDIA_DIR=/path/to/media

[!WARNING] Immich runs irreversible schema migrations on first start. Create a database backup before using an existing cluster. The cluster's PostgreSQL major version must match nix/shell.nix, which currently provides PostgreSQL 17.

The runner supports the following configuration variables:

VariablePurposeDefault
IMMICH_PREFIXAssembled application path.local/immich-app
IMMICH_STATE_DIRRuntime state root.local/immich-run
IMMICH_PGDATAPostgreSQL data directory$IMMICH_STATE_DIR/postgres
IMMICH_PGSOCKET_DIRPostgreSQL Unix-socket directory$TMPDIR/immich-nix-pgsocket
IMMICH_MEDIA_DIRImmich media directory$IMMICH_STATE_DIR/media
IMMICH_CACHE_DIRMachine-learning model cache$IMMICH_MEDIA_DIR/cache
IMMICH_HTTP_HOST, IMMICH_HTTP_PORTServer bind address and port0.0.0.0, 2283
IMMICH_ML_HOST, IMMICH_ML_PORTMachine-learning bind address and port127.0.0.1, 3003
IMMICH_PG_PORTPostgreSQL port5433
IMMICH_REDIS_HOST, IMMICH_REDIS_PORTValkey bind address and port127.0.0.1, 6380
IMMICH_DB_STORAGE_TYPEPostgreSQL tuning profile (SSD or HDD)SSD
IMMICH_DB_VECTOR_EXTENSIONForce pgvector or vectorchord; unset allows Immich to auto-select VectorChordunset
IMMICH_ML_WORKERSMachine-learning worker count1
IMMICH_ML_WORKER_TIMEOUTGunicorn timeout when the CoreML execution path is disabled300 seconds
MACHINE_LEARNING_DISABLE_COREMLSet to 1 to disable CoreML and run machine learning on CPUunset

Upstream compatibility

The current revision targets Immich v3.1.0 and was last tested against that release on macOS on 2026-09-03 and Linux on 2026-09-04. The status terms distinguish components built directly from upstream (“Aligned”), native or platform-specific implementations intended to preserve the same feature behavior (“Adapted”), and incomplete operational parity (“Partial”). This is a compatibility map, not a claim that the project reproduces every Docker-specific behavior or an exhaustive test matrix.

AreaStatusScope and differences
Server, API, and background workersAlignedBuilt from the pinned Immich source and run through the upstream node dist/main entry point.
Web applicationAlignedBuilt from the pinned Immich source and served by the Immich server.
Machine learningAdaptedUses upstream Python dependencies and CPU wheels. On Apple Silicon, a local patch routes smart search, face recognition, and OCR through model-specific CoreML representations; the SO400M text encoder remains on CPU. CoreML can be disabled.
Core WASM pluginAlignedBuilt from upstream source with the extism-js release and checksum pinned by Immich. Plugin loading must be checked after upgrades because failure is otherwise non-fatal.
Immich CLI and immich-adminAlignedBuilt from the pinned upstream source and installed with local wrappers.
Image and video processingAdaptedUses the upstream libvips build choices and loader-priority patch, plus Jellyfin FFmpeg and the required native codecs from Nix. Some library patch versions may be newer than the upstream image.
Reverse geocodingAlignedUses the geodata payload extracted from the exact production base image pinned by the Immich release.
PostgreSQL and vector searchAdaptedRuns PostgreSQL 17 with pgvector and VectorChord. Upstream database settings are translated where applicable; the macOS effective_io_concurrency exception is retained.
Existing pgvector databasesSupportedImmich can retain pgvector or migrate it to VectorChord. Set IMMICH_DB_VECTOR_EXTENSION=pgvector to postpone migration.
Legacy pgvecto.rs (vectors) databasesMigration requiredpgvecto.rs is not packaged. Such databases must follow Immich's standalone PostgreSQL migration procedure before use.
ValkeyAdaptedUses the Nix-provided Valkey package with Immich's existing Redis environment contract.
Scheduled database backupsAdaptedImmich's Debian-specific PostgreSQL binary path is patched to use the matching Nix-provided tools on PATH.
Process lifecycle and health monitoringPartialThe runner provides start, stop, restart, status, startup readiness checks, and logs. Docker restart policies and periodic container health checks are not reproduced.

Platform support:

PlatformStatusNotes
Apple Silicon macOS (aarch64-darwin)SupportedIncludes CoreML acceleration.
Intel macOS (x86_64-darwin)Not currently supportedNo matching extism-js release artifact is pinned. Nixpkgs is also dropping Intel Mac support.
Linux (aarch64-linux, x86_64-linux)SupportedThe flake and upstream-pinned extism-js artifacts cover both architectures; machine learning uses ONNX Runtime CPU.

The detailed alignment procedure, known divergences, and verification checklist are maintained in UPGRADING.md. Compatibility should be re-established whenever immich-version, flake.lock, or native library pins change.

Project structure

PathPurpose
LICENSEGNU Affero General Public License v3.0
UPGRADING.mdVersion-alignment process, failure modes, and verification checklist
immich-versionAuthoritative Immich release tag
flake.nix, flake.lockPinned nixpkgs input and development-shell outputs
nix/shell.nixToolchain, services, and native libraries
nix/extism-js.nixUpstream extism-js release artifact used to build the WASM plugin
nix/geodata.nixFixed-output reverse-geocoding data from the upstream image
nix/patches/libvips patch vendored from upstream base-images
scripts/build.shSource build and runtime-tree assembly
scripts/immich.shNative service runner
scripts/test.shDisposable native integration test runner
scripts/patch-postgres-bin-path.pyPostgreSQL backup-command path adaptation
scripts/patch-coreml.pyApple Silicon CoreML routing and CPU fallback
scripts/show-upstream-pins.shComparison of an Immich release with repository pins
tests/native-smoke.pyPublic API and deployed CLI media-lifecycle checks
tests/ml-smoke.pyReal CLIP, face-recognition, and OCR inference checks
upstream/immichPinned Immich source submodule used for the build
upstream/base-imagesPinned upstream native-library reference submodule
.local/immich-appGenerated application tree (ignored by Git)
.local/immich-runGenerated runtime state (ignored by Git)

Testing

Run the native integration suite against a fresh disposable database and media store:

nix develop --command scripts/test.sh quick

This checks the assembled build, starts the complete native stack on isolated ports, uploads generated photo and video fixtures through the deployed CLI, waits for metadata extraction, thumbnail generation, and video transcoding, verifies persistence across a complete restart, deletes the assets, and checks clean shutdown. It also verifies PostgreSQL checksums, VectorChord indexes, Valkey, the web application, the core plugin, and repository-local state.

The full mode additionally configures and exercises ViT-SO400M-16-SigLIP2-384__webli smart search, buffalo_l face recognition, and PP-OCRv5_server OCR through Immich, then calls each model family directly:

nix develop --command scripts/test.sh full

Model downloads are cached under .local/immich-test/model-cache; all other test state is recreated on every run. The integration suite covers this project's native adaptation boundary. The broader manual upgrade checklist in UPGRADING.md remains the release acceptance procedure.

Upgrading Immich

Read UPGRADING.md before changing the version. An upgrade can change the Node.js, pnpm, Python, extism-js, libvips, media-library, database, and service-runtime contracts in addition to the Immich source tag.

Begin by comparing the target release with the repository's pins:

nix develop --command scripts/show-upstream-pins.sh v3.2.0

After updating nix/ and immich-version, rebuild and complete the verification checklist in UPGRADING.md against both a fresh database and a disposable copy of the previous version's database. scripts/build.sh checks out the selected tag in upstream/immich; the resulting submodule pointer must be recorded as part of a version update.

Maintenance findings in UPGRADING.md are version-specific. The source tree, base-images revision, release notes, and official Immich documentation remain authoritative.

License

This project is licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). Immich, base-images, and other third-party components retain their respective copyrights and licenses.

Contributors

axonasif

43 commits

axonasif/immich-nix

Runs Immich natively on macOS (Apple Silicon) and Linux. No Docker, no VM. Nix based, with CoreML GPU hardware acceleration on macOS.

0

stars

43

commits

Shell

primary language

Sep 8, 2026

updated

README

immich-nix for macOS and Linux

Immich built and run natively with Nix, without Docker. Apple Silicon macOS and aarch64/x86_64 Linux are supported. GPU-accelerated machine learning is available on Apple Silicon through CoreML.

This project provides a low-complexity, single-host deployment designed for macOS and Linux. Nix supplies the build toolchain, native libraries, PostgreSQL, and Valkey, while Immich is built from its pinned upstream source with its own pnpm and uv workflows. Application data, runtime state, and build outputs remain inside the repository by default.

This is an independent deployment method, not an official Immich distribution. Upstream recommends Docker Compose for production installations.

CleanShot 2026-09-04 UTC 02 48 20@2x

Design

Packaging Immich as a conventional Nix derivation would require maintaining pnpmDeps hashes and a separate Python package set. It also encounters two Darwin-specific limitations: nixpkgs marks extism-js-core as broken on Darwin, and its ONNX Runtime build does not include the CoreML execution provider. Building with upstream's package managers avoids both constraints, at the cost of network-dependent, non-hermetic builds.

On Apple Silicon, the local machine-learning patch selects a working execution route for each model family. In testing on an M1 Pro, smart-search indexing reached 32–37 images per second with CoreML with the immich-app/ViT-SO400M-16-SigLIP2-384__webli model, compared with 3-10 images per second on CPU. With the smaller ViT-B-16-SigLIP2__webli model, you can get ~120 images per second on M1 Pro. The patch also avoids an ONNX Runtime issue that can expand the SO400M text model into a 6.5 GB CoreML program. See UPGRADING.md for the implementation rationale and measurements.

Requirements

  • Nix with flakes enabled
  • Apple Silicon macOS, or aarch64/x86_64 Linux

macOS does not require Homebrew or Xcode. System installations of Node.js and Python are not required on either platform. Your system is not polluted.

Installing Nix

For macOS, use the official multi-user installer:

curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh
Linux installation

For Linux systems using systemd with SELinux disabled, use the recommended multi-user installation:

curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh -s -- --daemon

After installation, start a new shell and enable the Nix command interface and flakes with the following commands:

mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf

See the official Nix download and installation instructions for other configurations, single-user installation, and troubleshooting.

Installation

The repository contains pinned Immich and base-images submodules and must be cloned recursively:

git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/axonasif/immich-nix.git
cd immich-nix

Build the complete stack once:

nix develop --command scripts/build.sh

Then start Immich:

nix develop --command scripts/immich.sh start

The web application is then available at http://0.0.0.0:2283. The initial build downloads the nixpkgs closure and application dependencies, then compiles sharp against the Nix-provided libvips. Subsequent builds reuse downloaded dependencies and are substantially faster.

By default, the assembled application is stored in .local/immich-app, while PostgreSQL, Valkey, logs, cached models, and media are stored in .local/immich-run. No files are installed system-wide. Consequently, removing the checkout also removes all data stored in these default locations.

Operation

Run nix develop to enter the immich env shell first to use the commands below easily.

scripts/immich.sh status
scripts/immich.sh logs
scripts/immich.sh stop
scripts/immich.sh restart

The upstream CLI and administration tool are included in the build:

export PATH="$PWD/.local/immich-app/bin:$PATH"
immich --help
immich-admin --help

Data locations and configuration

The default paths isolate a fresh checkout from any existing Immich installation. To use an existing PostgreSQL cluster or media library, define the relevant paths before starting the stack:

export IMMICH_PGDATA=/path/to/postgres
export IMMICH_MEDIA_DIR=/path/to/media

[!WARNING] Immich runs irreversible schema migrations on first start. Create a database backup before using an existing cluster. The cluster's PostgreSQL major version must match nix/shell.nix, which currently provides PostgreSQL 17.

The runner supports the following configuration variables:

VariablePurposeDefault
IMMICH_PREFIXAssembled application path.local/immich-app
IMMICH_STATE_DIRRuntime state root.local/immich-run
IMMICH_PGDATAPostgreSQL data directory$IMMICH_STATE_DIR/postgres
IMMICH_PGSOCKET_DIRPostgreSQL Unix-socket directory$TMPDIR/immich-nix-pgsocket
IMMICH_MEDIA_DIRImmich media directory$IMMICH_STATE_DIR/media
IMMICH_CACHE_DIRMachine-learning model cache$IMMICH_MEDIA_DIR/cache
IMMICH_HTTP_HOST, IMMICH_HTTP_PORTServer bind address and port0.0.0.0, 2283
IMMICH_ML_HOST, IMMICH_ML_PORTMachine-learning bind address and port127.0.0.1, 3003
IMMICH_PG_PORTPostgreSQL port5433
IMMICH_REDIS_HOST, IMMICH_REDIS_PORTValkey bind address and port127.0.0.1, 6380
IMMICH_DB_STORAGE_TYPEPostgreSQL tuning profile (SSD or HDD)SSD
IMMICH_DB_VECTOR_EXTENSIONForce pgvector or vectorchord; unset allows Immich to auto-select VectorChordunset
IMMICH_ML_WORKERSMachine-learning worker count1
IMMICH_ML_WORKER_TIMEOUTGunicorn timeout when the CoreML execution path is disabled300 seconds
MACHINE_LEARNING_DISABLE_COREMLSet to 1 to disable CoreML and run machine learning on CPUunset

Upstream compatibility

The current revision targets Immich v3.1.0 and was last tested against that release on macOS on 2026-09-03 and Linux on 2026-09-04. The status terms distinguish components built directly from upstream (“Aligned”), native or platform-specific implementations intended to preserve the same feature behavior (“Adapted”), and incomplete operational parity (“Partial”). This is a compatibility map, not a claim that the project reproduces every Docker-specific behavior or an exhaustive test matrix.

AreaStatusScope and differences
Server, API, and background workersAlignedBuilt from the pinned Immich source and run through the upstream node dist/main entry point.
Web applicationAlignedBuilt from the pinned Immich source and served by the Immich server.
Machine learningAdaptedUses upstream Python dependencies and CPU wheels. On Apple Silicon, a local patch routes smart search, face recognition, and OCR through model-specific CoreML representations; the SO400M text encoder remains on CPU. CoreML can be disabled.
Core WASM pluginAlignedBuilt from upstream source with the extism-js release and checksum pinned by Immich. Plugin loading must be checked after upgrades because failure is otherwise non-fatal.
Immich CLI and immich-adminAlignedBuilt from the pinned upstream source and installed with local wrappers.
Image and video processingAdaptedUses the upstream libvips build choices and loader-priority patch, plus Jellyfin FFmpeg and the required native codecs from Nix. Some library patch versions may be newer than the upstream image.
Reverse geocodingAlignedUses the geodata payload extracted from the exact production base image pinned by the Immich release.
PostgreSQL and vector searchAdaptedRuns PostgreSQL 17 with pgvector and VectorChord. Upstream database settings are translated where applicable; the macOS effective_io_concurrency exception is retained.
Existing pgvector databasesSupportedImmich can retain pgvector or migrate it to VectorChord. Set IMMICH_DB_VECTOR_EXTENSION=pgvector to postpone migration.
Legacy pgvecto.rs (vectors) databasesMigration requiredpgvecto.rs is not packaged. Such databases must follow Immich's standalone PostgreSQL migration procedure before use.
ValkeyAdaptedUses the Nix-provided Valkey package with Immich's existing Redis environment contract.
Scheduled database backupsAdaptedImmich's Debian-specific PostgreSQL binary path is patched to use the matching Nix-provided tools on PATH.
Process lifecycle and health monitoringPartialThe runner provides start, stop, restart, status, startup readiness checks, and logs. Docker restart policies and periodic container health checks are not reproduced.

Platform support:

PlatformStatusNotes
Apple Silicon macOS (aarch64-darwin)SupportedIncludes CoreML acceleration.
Intel macOS (x86_64-darwin)Not currently supportedNo matching extism-js release artifact is pinned. Nixpkgs is also dropping Intel Mac support.
Linux (aarch64-linux, x86_64-linux)SupportedThe flake and upstream-pinned extism-js artifacts cover both architectures; machine learning uses ONNX Runtime CPU.

The detailed alignment procedure, known divergences, and verification checklist are maintained in UPGRADING.md. Compatibility should be re-established whenever immich-version, flake.lock, or native library pins change.

Project structure

PathPurpose
LICENSEGNU Affero General Public License v3.0
UPGRADING.mdVersion-alignment process, failure modes, and verification checklist
immich-versionAuthoritative Immich release tag
flake.nix, flake.lockPinned nixpkgs input and development-shell outputs
nix/shell.nixToolchain, services, and native libraries
nix/extism-js.nixUpstream extism-js release artifact used to build the WASM plugin
nix/geodata.nixFixed-output reverse-geocoding data from the upstream image
nix/patches/libvips patch vendored from upstream base-images
scripts/build.shSource build and runtime-tree assembly
scripts/immich.shNative service runner
scripts/test.shDisposable native integration test runner
scripts/patch-postgres-bin-path.pyPostgreSQL backup-command path adaptation
scripts/patch-coreml.pyApple Silicon CoreML routing and CPU fallback
scripts/show-upstream-pins.shComparison of an Immich release with repository pins
tests/native-smoke.pyPublic API and deployed CLI media-lifecycle checks
tests/ml-smoke.pyReal CLIP, face-recognition, and OCR inference checks
upstream/immichPinned Immich source submodule used for the build
upstream/base-imagesPinned upstream native-library reference submodule
.local/immich-appGenerated application tree (ignored by Git)
.local/immich-runGenerated runtime state (ignored by Git)

Testing

Run the native integration suite against a fresh disposable database and media store:

nix develop --command scripts/test.sh quick

This checks the assembled build, starts the complete native stack on isolated ports, uploads generated photo and video fixtures through the deployed CLI, waits for metadata extraction, thumbnail generation, and video transcoding, verifies persistence across a complete restart, deletes the assets, and checks clean shutdown. It also verifies PostgreSQL checksums, VectorChord indexes, Valkey, the web application, the core plugin, and repository-local state.

The full mode additionally configures and exercises ViT-SO400M-16-SigLIP2-384__webli smart search, buffalo_l face recognition, and PP-OCRv5_server OCR through Immich, then calls each model family directly:

nix develop --command scripts/test.sh full

Model downloads are cached under .local/immich-test/model-cache; all other test state is recreated on every run. The integration suite covers this project's native adaptation boundary. The broader manual upgrade checklist in UPGRADING.md remains the release acceptance procedure.

Upgrading Immich

Read UPGRADING.md before changing the version. An upgrade can change the Node.js, pnpm, Python, extism-js, libvips, media-library, database, and service-runtime contracts in addition to the Immich source tag.

Begin by comparing the target release with the repository's pins:

nix develop --command scripts/show-upstream-pins.sh v3.2.0

After updating nix/ and immich-version, rebuild and complete the verification checklist in UPGRADING.md against both a fresh database and a disposable copy of the previous version's database. scripts/build.sh checks out the selected tag in upstream/immich; the resulting submodule pointer must be recorded as part of a version update.

Maintenance findings in UPGRADING.md are version-specific. The source tree, base-images revision, release notes, and official Immich documentation remain authoritative.

License

This project is licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). Immich, base-images, and other third-party components retain their respective copyrights and licenses.

Contributors

axonasif

43 commits

Languages

Shell

46.7%

Python

43.6%

Nix

9.7%