TRENDSHIFT GitHub Trending #20 · 2026.05.23 · immich-app/immich

내 서버에서 돌리는
Google Photos

101k stars · 5.6k forks · 10,053 commits · AGPL-3.0. NestJS + SvelteKit + Flutter + Python ML 4-스택 모노레포로 만든 셀프호스팅 사진/영상 관리 솔루션. CLIP 시맨틱 검색 + 얼굴 인식 + OCR + 지도까지 다 한다. Google Photos를 내 NAS에서 굴리는 것.

0먼저, Immich가 뭔가?

아주 기초부터 — "셀프호스팅"이 뭐고 왜 이게 인기인가.

스마트폰으로 찍은 사진은 자동으로 어디론가 백업된다. 아이폰은 iCloud, 안드로이드는 Google Photos. 둘 다 편하지만 같은 문제를 안고 있다 — "내 사진이 남의 회사 서버에 산다"는 점, 그리고 "무료 용량이 끝나면 매달 돈을 내야 한다"는 점.

용어
셀프호스팅 (Self-hosting)
남의 클라우드 대신 내 컴퓨터(또는 NAS, 서버)에 직접 소프트웨어를 설치해서 돌리는 방식. 데이터 주권을 100% 갖고, 구독료가 사라지고, 인터넷이 끊겨도 동작한다. 단점 — 백업·보안·업데이트를 내가 책임진다.
용어
NAS (Network Attached Storage)
집이나 사무실 네트워크에 항상 켜져 있는 작은 파일 서버. 시놀로지(Synology)·QNAP·UnRAID가 대표적. 보통 하드디스크 2~6개를 RAID로 묶어 큰 용량을 만든다. Immich를 돌릴 가장 자연스러운 환경 중 하나.

Immich는 이 문제를 정조준한 프로젝트다. Google Photos에서 보던 거의 모든 기능 — 자동 백업, 얼굴별 묶기, "1년 전 오늘" 추억, 검색창에 "강아지"라고 치면 강아지 사진이 뜨는 마법 — 을 내가 가진 서버에서 똑같이 돌릴 수 있게 해준다. 게다가 라이선스가 AGPL-3.0이라 소스 코드도 완전 공개되어 있다.

비유

아파트 공용 세탁소(Google Photos)는 편하다. 세제도 알아서 챙겨주고, 고장나면 관리실에서 고친다. 그런데 어느 날 관리실이 "1kg당 한 달에 천 원씩 받습니다"라고 통보한다. 빨래 양이 많으면 화가 난다. 그리고 누가 내 빨래를 만지는지 정확히 모른다.

Immich는 내 집 베란다에 직접 설치하는 세탁기다. 초기에 기계값(서버·하드디스크)이 들고, 가끔 필터도 청소해야 하지만, 한 번 사두면 추가 비용은 거의 0. 무엇보다 누가 내 빨래를 봤는지 100% 통제할 수 있다.

1프로젝트 한줄 요약

이 글의 핵심 메시지.

핵심 메시지

"Google Photos 기능 99%를
4개 Docker 컨테이너로 내 NAS에 옮기는 풀스택 프로젝트."

Immich는 단순한 사진 갤러리 앱이 아니다. NestJS 백엔드 + SvelteKit 웹 + Flutter 모바일 + Python ML 네 개의 거대한 서브 프로젝트가 한 모노레포 안에 살면서, PostgreSQL + Redis + ONNX Runtime 위에서 협력한다.

그 결과 — 자동 백업, EXIF 메타데이터 파싱, CLIP 임베딩 기반 시맨틱 검색("해변", "고양이", "빨간 자동차"로 검색 가능), InsightFace 얼굴 인식 + 클러스터링, RapidOCR로 사진 속 글자 검색, MapLibre 지도 위에 사진 표시, 360도 파노라마, 라이브포토 재생 — 이 모든 게 전부 무료로, 내 서버 안에서 돌아간다.

2왜 주목받는가

101k stars · GitHub Trending 40번 등장 — 인기의 이유.

Trendshift 데이터로 보면 Immich는 GitHub Trending 페이지에 지금까지 총 40번 올랐다. 셀프호스팅 사진 관리라는 좁아 보이는 분야에서 이만한 모멘텀을 유지하는 이유는 명확하다.

이유 1

"Google Photos를 떠나는 사람" 흐름과 정확히 맞물림

2021년 Google이 무료 무제한 백업을 종료한 이후, "내 사진을 어디로 옮길까"가 매년 화두였다. PhotoPrism, Piwigo, Lychee 등 경쟁자가 있지만 모바일 앱 완성도 + AI 기능 + 모던한 UI 세 박자를 동시에 갖춘 건 Immich가 거의 유일했다. 특히 iOS/Android 네이티브 앱이 자동 백업 백그라운드 작업까지 안정적으로 돌리는 것이 결정타.

이유 2

FUTO의 후원 — 진짜 회사가 만든다

주 메인테이너 Alex Tran은 처음 개인 프로젝트로 시작했지만, 2024년부터 텍사스 오스틴의 FUTO(전 SpaceX 엔지니어 Eron Wolf가 세운 비영리 OSS 후원 재단)가 풀타임 고용했다. "오픈소스이지만 진짜 회사처럼 굴러가는" 보기 드문 형태다. v2.7.5(2026.04)까지 296번의 릴리스, 평균 1~2주에 한 번 안정 릴리스가 나온다.

이유 3

"Docker Compose 한 줄로 끝나는" 셀프호스팅 정석

설치 가이드의 핵심은 docker-compose.yml + .env 두 파일. 4개 컨테이너(immich-server, immich-machine-learning, redis, postgres)가 자동으로 묶여 뜬다. 시놀로지 NAS, Unraid, Proxmox, Raspberry Pi 5 등 어디에 설치하든 가이드가 잘 정리돼 있다. "셀프호스팅 입문 프로젝트"로 추천되는 자리를 확실히 잡았다.

이유 4

다국어 — 한국어 포함 18+개 언어 README

레포 루트의 readme_i18n/ 폴더에 18개 언어 README가 있고, 그중 한국어(README_ko_KR.md)도 정식으로 관리된다. Weblate 기반 번역 워크플로(hosted.weblate.org/engage/immich)로 UI까지 한국어 지원. 한국인 사용자 비중도 크다.

비유

Immich는 스시집 카운터에 자리잡은 외국인 셰프다. 일본인 셰프(Google Photos)만 있던 동네에서 "재료 다 보여드리고, 칼질도 직접 보세요"라는 투명함으로 손님을 끌었다. 더해서 메뉴판이 18개 언어로 번역돼 있어서 누구나 편안하게 주문할 수 있다.

3기술 스택 전체 지도

백엔드·프론트·모바일·ML — 4개 거대 스택을 한 모노레포에 묶었다.

Immich 레포의 언어 비중을 보면 그림이 명확해진다 — TypeScript 52.5% + Dart 28.2% + Svelte 13.9% + Python 1.6% + Kotlin 1.3% + Swift 1.1%. 즉 백엔드와 웹은 TS로 통일, 모바일은 Flutter(Dart), 머신러닝 서비스만 Python으로 분리한 구조다. 이 6개 언어를 pnpm workspace + Docker Compose로 묶어 운영한다.

3.1 백엔드 — NestJS 11 + Kysely + BullMQ

용어
NestJS (Node.js 풀스택 프레임워크)
Java Spring처럼 데코레이터(@Controller, @Injectable)와 의존성 주입(DI)으로 큰 백엔드를 구조화하는 TypeScript 프레임워크. Express 위에 얹어 쓴다. Immich 서버는 v11(2025년 출시 최신)을 사용.
용어
Kysely (타입 안전한 SQL 빌더)
전통적인 ORM(Prisma·TypeORM)과 달리 SQL을 그대로 쓰되 컴파일 시점에 타입 체크를 해주는 가벼운 빌더. Immich가 v1.x → v2 마이그레이션 시 TypeORM에서 Kysely로 갈아탄 이유는 "우리가 쓰는 PostgreSQL 기능을 ORM이 다 못 표현해서". 벡터 검색 같은 고급 쿼리를 직접 짠다.
용어
BullMQ + Redis(Valkey 9)
사진 1만 장을 업로드하면 — 썸네일 만들기, EXIF 추출, CLIP 임베딩, 얼굴 인식, 트랜스코딩 등 작업이 폭증한다. BullMQ는 이 작업들을 Redis 큐에 쌓고, 워커 프로세스가 우선순위/동시성을 지키며 하나씩 처리한다. Immich는 Redis 대신 fork인 Valkey(2024년 Redis Inc.가 라이선스를 바꾼 뒤 Linux Foundation이 만든 OSS 포크)를 쓴다.

핵심 의존성(server/package.json에서 발췌)

"@nestjs/core": "^11.0.4"          ← 프레임워크
"@nestjs/bullmq": "^11.0.1"        ← 작업 큐 통합
"kysely": "0.28.17"                ← SQL 빌더
"postgres": "3.4.9"                ← PG 드라이버(porsager)
"sharp": "^0.34.5"                 ← 이미지 리사이즈 (libvips 기반, 초고속)
"fluent-ffmpeg": "^2.1.2"          ← 비디오 트랜스코딩 래퍼
"exiftool-vendored": "^35.20.0"    ← EXIF 메타데이터(geo, camera, etc.)
"geo-tz": "^8.0.0"                 ← 위경도 → 타임존 변환
"socket.io": "^4.8.1"              ← 실시간 알림(업로드 진행률 등)
"@opentelemetry/sdk-node"          ← 분산 트레이싱
"@extism/extism": "2.0.0-rc13"     ← WebAssembly 플러그인 런타임
"react-email": "^5.0.0"            ← 메일 템플릿(JSX로 작성)
"zod": "4.3.6"                     ← 런타임 스키마 검증

흥미로운 선택이 두 개 있다. 하나는 Sharp — Node 진영의 사실상 표준 이미지 처리 라이브러리지만 내부는 libvips(C)다. 다른 하나는 Extism — Wasm 기반 플러그인 런타임으로, Immich는 @immich/plugin-sdk를 통해 사용자 작성 플러그인을 안전한 샌드박스에서 실행할 수 있게 가는 중이다(v3 로드맵).

3.2 프론트엔드 — SvelteKit + Svelte 5 + Tailwind 4

용어
SvelteKit (Svelte 기반 풀스택 프레임워크)
React의 Next.js, Vue의 Nuxt에 해당하는 Svelte 진영의 메타프레임워크. Immich 웹은 @sveltejs/adapter-static을 써서 SSG(Static Site Generation)로 빌드 → NestJS 서버가 정적 파일을 서빙하는 구조다. SPA처럼 빠르되 백엔드는 별도.
용어
Svelte 5 + Runes
Svelte 5는 React Hooks 같은 $state, $derived, $effect "룬(Runes)"을 도입했다. 더 명시적이지만 React보다 코드 양이 적다. Immich는 2024년 말 Svelte 4 → 5 마이그레이션을 완료했다.

특이 의존성(web/package.json)

"@immich/justified-layout-wasm"  ← Flickr/구글포토 식 "정렬된 갤러리"
                                    레이아웃 계산을 WebAssembly로
"maplibre-gl": "^5.6.2"          ← Mapbox 무료 fork. 사진 지도 표시
"pmtiles": "^4.3.0"              ← 단일 파일 타일 포맷(자체 호스팅)
"@photo-sphere-viewer/core"      ← 360도 파노라마 뷰어
"media-chrome": "^4.19.0"        ← 영상 플레이어 UI 컴포넌트
"thumbhash": "^0.1.1"            ← 흐릿한 썸네일 압축 포맷(~25바이트)
"svelte-i18n": "^4.0.1"          ← 다국어
"fabric": "^7.0.0"               ← 캔버스(이미지 편집)
"qrcode": "^1.5.4"               ← 모바일 페어링용

justified-layout-wasm은 Immich가 자체 개발한 패키지다. 갤러리에 5만 장을 한 번에 뿌릴 때 자바스크립트로 레이아웃 계산하면 메인 스레드가 멈춘다 → WebAssembly로 짜서 Web Worker에 넣어 60fps 유지한다. 이런 디테일이 "왜 Immich가 빠른가"를 만든다.

3.3 모바일 — Flutter

모바일 폴더는 Flutter(Dart 28.2%) + 네이티브 코드(Kotlin 1.3% Android, Swift 1.1% iOS)로 구성된다. 핵심 기능은 "백그라운드 자동 백업"인데, 이건 OS의 깊은 곳에 손대야 하기 때문에 순수 Flutter로 안 된다.

용어
Flutter (구글의 크로스플랫폼 UI 프레임워크)
한 번 짜면 iOS·Android(·웹·데스크탑)에서 모두 동작하는 UI 프레임워크. Dart 언어. React Native와 달리 자체 렌더링 엔진(Impeller/Skia)을 들고 다녀 네이티브에 가까운 성능. Immich가 React Native가 아니라 Flutter를 택한 큰 이유 중 하나는 이미지 그리드 스크롤 성능.

3.4 머신러닝 — Python 3.11 + FastAPI + ONNX Runtime

용어
ONNX Runtime
PyTorch·TensorFlow로 학습한 모델을 ONNX(Open Neural Network Exchange) 포맷으로 변환해 어디서든 빠르게 추론하는 런타임. Immich는 5종 하드웨어 가속(CPU·CUDA·OpenVINO·ArmNN·RKNN·ROCm)을 pyproject.tomloptional dependencies로 분리해 둠 — 사용자가 자기 환경에 맞는 백엔드만 설치한다.

머신러닝 의존성(machine-learning/pyproject.toml)

fastapi >= 0.95.2                ← 비동기 REST API
gunicorn >= 21.1.0               ← ASGI 워커 프로세스 관리자 (uvicorn 워커 구동용)
huggingface-hub >= 1.0           ← 모델 다운로드
insightface >= 0.7.3             ← 얼굴 검출 + 임베딩
opencv-python-headless           ← 이미지 전처리
tokenizers >= 0.15.0             ← HF tokenizer
rapidocr >= 3.1.0                ← OCR(PaddleOCR 경량화 fork)

[optional-dependencies]
cpu      = ["onnxruntime"]
cuda     = ["onnxruntime-gpu"]
openvino = ["onnxruntime-openvino"]
armnn    = ["onnxruntime"]
rknn     = ["onnxruntime", "rknn-toolkit-lite2"]
rocm     = ["onnxruntime-migraphx"]

핵심 3가지 ML 능력 —

3.5 데이터 레이어 — PostgreSQL + VectorChord + pgvecto.rs

docker-compose.yml을 보면 DB 이미지가 특이하다 —

image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0

PostgreSQL 14 + VectorChord + pgvecto.rsImmich가 직접 빌드한 커스텀 이미지다. 두 개의 벡터 검색 확장이 같이 들어있다.

용어
pgvecto.rs / pgvector / VectorChord
PostgreSQL에 벡터(임베딩) 검색을 추가하는 확장. 사진의 CLIP 임베딩(512차원 벡터)이나 얼굴 임베딩(512차원)을 저장하고, "이 벡터와 비슷한 것 100개 찾아줘"를 빠르게 한다. pgvecto.rs는 Rust 구현, VectorChord는 더 빠른 차세대 인덱스(IVF + RaBitQ). Immich는 두 가지를 같이 쓰면서 마이그레이션하는 중이다.

3.6 인프라/배포 — Docker + GHCR + 멀티 아키텍처

ghcr.io/immich-app/immich-serverghcr.io/immich-app/immich-machine-learning 두 이미지를 GitHub Container Registry에 자동 배포. 머신러닝 이미지는 가속기별로 태그가 갈린다 — :release, :release-cuda, :release-rocm, :release-openvino, :release-armnn, :release-rknn. 사용자는 자기 하드웨어에 맞는 태그를 docker-compose에 적기만 하면 된다.

비유

Immich의 기술 스택은 여행 도시락이다. 메인 반찬은 NestJS+Postgres(밥), 사이드는 SvelteKit(과일), 디저트는 Flutter 앱(쿠키), 그리고 별도 보온 도시락에 Python ML(국). 각각 따로 만들어 식판에 모은다. 한 번에 다 꺼내 먹어야 진짜 한 끼가 된다.

4아키텍처 심화 분석

사진 한 장이 업로드된 후 일어나는 일을 단계별로.

4.1 4-컨테이너 토폴로지

공식 docker-compose.yml의 핵심 구조는 단순하다 — 컨테이너 4개가 도커 네트워크 안에서 통신한다.

┌─────────────────────────────────────────────────────────────────────┐
│                    Docker Compose Network: immich                   │
│                                                                     │
│  ┌──────────────────┐         ┌─────────────────────────────┐       │
│  │  immich_server   │ ◄────► │  immich_machine_learning    │       │
│  │  (NestJS 11)     │  HTTP   │  (FastAPI + ONNX Runtime)   │       │
│  │  Port 2283       │         │  Port 3003 (내부)            │       │
│  │  - REST API      │         │  - CLIP 임베딩              │       │
│  │  - WebSocket     │         │  - InsightFace 얼굴 검출    │       │
│  │  - BullMQ 워커   │         │  - RapidOCR 텍스트 추출     │       │
│  │  - Sharp/ffmpeg  │         │  GPU 가속 옵션 5종           │       │
│  └────┬─────────┬───┘         └──────────────┬──────────────┘       │
│       │         │                            │                      │
│       │         │                            │                      │
│       ▼         ▼                            ▼                      │
│  ┌─────────┐  ┌──────────────────────────────────────────┐          │
│  │ Valkey  │  │  Postgres 14 + VectorChord + pgvecto.rs  │          │
│  │ (Redis) │  │  - 사진 메타데이터                       │          │
│  │ - 큐    │  │  - 사용자/앨범                           │          │
│  │ - 세션  │  │  - CLIP/얼굴 임베딩 벡터 인덱스          │          │
│  └─────────┘  └──────────────────────────────────────────┘          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
                            │
                            ▼ 마운트
                  ┌──────────────────────┐
                  │  ${UPLOAD_LOCATION}  │   ← 호스트의 사진 보관소
                  │  /mnt/photos/        │     (NAS 디스크)
                  └──────────────────────┘

4.2 사진 한 장의 여정 — 업로드부터 검색까지

[1] 모바일 앱이 사진 1장을 POST /api/asset로 업로드
        │
        ▼
[2] immich_server (NestJS) 가 받음
    ├─ Multer로 멀티파트 파일 파싱
    ├─ SHA1 해시 계산 → 중복 검사(같은 해시 있으면 409 반환)
    ├─ 원본을 /data/upload//...에 저장
    └─ DB에 INSERT (state = 'unprocessed')
        │
        ▼
[3] BullMQ로 6개 작업이 큐에 들어감
    ├─ metadata-extraction     (ExifTool로 EXIF 추출 — 카메라/지오태그/일시)
    ├─ thumbnail-generation    (Sharp로 preview/webp + thumbnail 생성)
    ├─ video-conversion        (영상이면 ffmpeg로 트랜스코딩)
    ├─ smart-search            (CLIP 임베딩 요청 → ML 컨테이너 → DB)
    ├─ face-detection          (InsightFace SCRFD로 얼굴 박스 검출)
    └─ ocr                     (RapidOCR로 사진 속 글자 추출)
        │
        ▼
[4] 각 워커가 병렬로 처리(BullMQ 동시성 설정)
    └─ ML 작업은 immich_machine_learning에 HTTP POST
       → ONNX Runtime이 GPU/CPU에서 추론
       → 결과 임베딩 512차원 벡터를 Postgres에 저장
        │
        ▼
[5] face-detection 완료 후 face-recognition 큐가 트리거
    └─ 검출된 얼굴 임베딩과 기존 클러스터를 비교
       → 같은 사람이면 기존 person_id에 붙이고
       → 새 사람이면 새 person 레코드 생성
        │
        ▼
[6] 모든 작업 완료 시 Socket.IO로 모바일 앱에 알림
    └─ "백업 완료! 검색에 곧 반영됩니다"
        │
        ▼
[7] 이후 사용자가 "강아지"라고 검색하면:
    ├─ 검색어를 ML 컨테이너에서 CLIP 텍스트 임베딩으로 변환
    └─ Postgres에서 코사인 유사도 가장 가까운 100개 사진 반환
       (VectorChord IVF 인덱스로 100ms 이내)

4.3 핵심 설계 패턴

패턴 1 — Worker Queue Architecture

"업로드는 빠르게 받고, 무거운 작업은 백그라운드로"

업로드 응답은 1초 안에 끝나야 모바일 앱이 다음 사진을 보낸다. 하지만 EXIF 추출·CLIP 임베딩·얼굴 인식은 사진 1장당 수 초 걸린다. 해결법은 BullMQ 큐 — "DB에 INSERT만 하고 작업을 큐에 던져 즉시 반환". 워커가 나중에 처리한다. 만 장을 한꺼번에 보내도 서버가 안 죽는다.

패턴 2 — ML 서비스 분리

"파이썬 ML과 노드 백엔드는 다른 컨테이너"

Python으로 NestJS와 같은 프로세스에서 ML 돌리면 메모리/의존성 지옥이다. Immich는 둘을 HTTP API로 분리해서 NestJS 서버는 ML 컨테이너에 POST /predict만 한다. ML 컨테이너는 단독 스케일링 가능 — 사진이 많으면 ML만 GPU 서버에 따로 띄울 수 있다.

패턴 3 — Optional Dependencies로 슬림 설치

"NVIDIA GPU 없는 사람한테 cuda를 깔리지 않는다"

ML 컨테이너 이미지가 6가지 태그(cpu/cuda/rocm/openvino/armnn/rknn)로 나뉘는 비결은 pyproject.toml[project.optional-dependencies]. Dockerfile에서 uv pip install '.[cuda]' 같이 빌드 타임에 가속기를 결정한다. CPU 이미지는 1GB, CUDA 이미지는 5GB. 사용자는 자기 하드웨어에 맞는 것 하나만 받는다.

패턴 4 — Vector DB로 일원화

"검색용 DB를 따로 두지 않는다"

벡터 검색이 필요하면 Pinecone/Weaviate/Qdrant 같은 별도 벡터 DB를 띄우는 게 일반적이다. Immich는 PostgreSQL 안에 VectorChord 확장으로 처리 — 운영 컨테이너 수가 줄고, 트랜잭션도 한 DB 안에서 관리된다. "사진 메타데이터 + 벡터"가 한 트랜잭션에 묶이는 게 장점.

패턴 5 — 워크스페이스 모노레포 + 공유 패키지

"server·web·mobile이 SDK 패키지를 공유한다"

packages/ 폴더에 @immich/sdk(OpenAPI 자동 생성 TypeScript 클라이언트), @immich/ui(Svelte 컴포넌트), @immich/plugin-sdk가 있다. server가 OpenAPI 스펙 발행 → openapi-generator가 SDK 생성 → web과 mobile이 사용하는 파이프라인이라 API 변경 시 타입이 자동 동기화된다.

5디렉토리 구조 해부

레포 루트의 폴더 17개가 각각 무슨 역할인지.

immich/
├── server/                ← NestJS 백엔드. 사실상 두뇌. TS 52.5% 비중의 절반.
│   ├── src/
│   │   ├── controllers/   ← REST API 엔드포인트 (Asset, Album, Search 등)
│   │   ├── services/      ← 비즈니스 로직
│   │   ├── repositories/  ← Kysely 기반 DB 접근
│   │   ├── queries/       ← 복잡한 SQL 쿼리(벡터 검색 등)
│   │   ├── workers/       ← BullMQ 백그라운드 작업 핸들러
│   │   ├── emails/        ← React Email JSX 템플릿
│   │   └── schema/        ← DB 마이그레이션 + 테이블 정의
│   └── package.json       ← 코어 의존성 ~80개
│
├── web/                   ← SvelteKit 프론트엔드. 13.9% Svelte.
│   ├── src/
│   │   ├── lib/           ← 재사용 컴포넌트(Map, Viewer, Album 등)
│   │   ├── routes/        ← 페이지 라우팅(/photos, /albums, /map 등)
│   │   └── hooks.server.ts ← 인증 미들웨어
│   └── package.json
│
├── mobile/                ← Flutter 모바일 앱. Dart 28.2%.
│   ├── lib/               ← Dart 소스
│   ├── android/           ← Kotlin 1.3% (백그라운드 워커 등)
│   ├── ios/               ← Swift 1.1% (PhotoKit 통합)
│   └── pubspec.yaml       ← Flutter 의존성
│
├── machine-learning/      ← Python FastAPI ML 서비스. Python 1.6%.
│   ├── immich_ml/
│   │   ├── models/        ← CLIP, InsightFace, RapidOCR 래퍼
│   │   ├── sessions/      ← ONNX Runtime 세션(가속기별)
│   │   └── main.py        ← FastAPI 진입점
│   └── pyproject.toml     ← uv 빌드 설정
│
├── packages/              ← 워크스페이스 공유 패키지 (모노레포 코어)
│   ├── sdk/               ← @immich/sdk — OpenAPI 자동 생성 TS 클라이언트
│   ├── plugin-sdk/        ← @immich/plugin-sdk — Wasm 플러그인 SDK
│   ├── plugin-core/       ← 플러그인 코어 로직
│   ├── cli/               ← Immich CLI 도구
│   └── e2e-auth-server/   ← E2E 테스트용 인증 서버
│   (※ @immich/ui · @immich/justified-layout-wasm 은 이 모노레포 외부 npm 패키지)
│
├── open-api/              ← OpenAPI(Swagger) 스펙 정의
│   └── immich-openapi-specs.json  ← server가 자동 생성
│
├── docker/                ← Docker Compose 파일들
│   ├── docker-compose.yml ← 표준 배포
│   ├── docker-compose.dev.yml  ← 개발용
│   ├── hwaccel.ml.yml     ← ML 가속기별 설정(GPU 마운트 등)
│   └── hwaccel.transcoding.yml  ← 비디오 트랜스코딩 가속
│
├── e2e/                   ← Playwright E2E 테스트
│   ├── src/api/           ← API 테스트
│   ├── src/web/           ← 웹 UI 테스트
│   └── src/mobile/        ← 모바일 E2E
│
├── docs/                  ← Docusaurus 공식 문서 사이트
│   └── docs/              ← Markdown 문서 (docs.immich.app 호스팅)
│
├── i18n/                  ← Weblate 동기화되는 번역 파일
│   ├── ko.json            ← 한국어
│   ├── en.json            ← 영어
│   └── ... (수십 개 언어)
│
├── readme_i18n/           ← 18개 언어 README 번역
│   └── README_ko_KR.md    ← 한국어 README
│
├── deployment/            ← 운영 배포용 스크립트(Portainer/K8s 등)
├── design/                ← 로고, 스크린샷, SVG 자산
├── fastlane/              ← iOS/Android 앱스토어 자동 배포 설정
├── misc/release/          ← 릴리스 노트 생성 스크립트
├── install.sh             ← 원라이너 설치 스크립트(curl | bash)
├── mise.toml              ← 개발 환경(node·python·rust 버전) 핀
└── pnpm-workspace.yaml    ← pnpm 모노레포 정의

중요한 폴더 3개를 짚으면 — packages/는 "쪼개진 듯 묶여있는" 모노레포의 핵심이다. i18n/은 글로벌 사용자 친화의 증거. e2e/는 4-스택 시스템을 끝까지 검증하는 보험.

6학습 포인트 (기술별)

Immich 레포에서 뽑아갈 수 있는 실용 지식 6묶음.

학습 포인트 1

NestJS 풀스택 구조 학습 교본

NestJS는 한국에서 인지도가 낮지만 글로벌에선 거대한 풀스택 백엔드의 정석이다. Immich의 server/srcController → Service → Repository 3계층이 명확히 분리돼 있고, @nestjs/bullmq로 워커 큐, @nestjs/swagger로 OpenAPI 자동 생성, @nestjs/schedule로 크론 작업까지 — NestJS의 거의 모든 기능을 실제 production 코드로 본다.

실습 아이디어: server/src/controllers/asset.controller.ts를 읽고, 자기 프로젝트에서 비슷한 3계층 구조를 흉내내본다.

학습 포인트 2

모노레포에서 코드 공유하는 법

여러 패키지가 같은 타입/함수를 쓸 때 보통 npm publish하기 귀찮다. Immich는 pnpm workspace + workspace:* 프로토콜로 해결 — "@immich/sdk": "workspace:*"라고 적으면 동일 레포의 패키지를 그대로 import한다. 빌드 시 자동 링크.

실습 아이디어: 새 pnpm workspace를 만들고 packages/sharedapps/api로 분리해본다.

학습 포인트 3

벡터 검색(시맨틱 서치)을 PostgreSQL에서 하기

"OpenAI 임베딩 만들었는데 어디 저장하지?"의 정석 답은 보통 Pinecone이다. Immich는 PostgreSQL + pgvecto.rs/VectorChord로 한 DB에서 처리한다. 코드를 보면 SELECT * FROM assets ORDER BY embedding <=> $1 LIMIT 100 같은 SQL이 그대로 보인다(<=>는 코사인 거리).

실습 아이디어: 로컬 Postgres에 pgvector 확장 깔고, OpenAI 임베딩 API로 블로그 글 검색기를 만들어본다.

학습 포인트 4

이미지·영상 처리 파이프라인의 표준

썸네일 만들기 = sharp.resize(256).webp().toFile(). 영상 트랜스코딩 = fluent-ffmpeg().videoCodec('h264_nvenc').size('?x720'). EXIF 추출 = exiftool.read(path). 사진/영상 다루는 모든 Node.js 프로젝트가 결국 이 세 가지를 거친다 — Immich가 production에서 어떻게 쓰는지 그대로 카피해도 된다.

실습 아이디어: 폴더의 모든 이미지를 Sharp로 webp 변환하고 EXIF로 카메라 모델별 통계를 내는 CLI를 만든다.

학습 포인트 5

Python ML을 Node 백엔드와 결합하는 표준 패턴

"Node에서 PyTorch 모델 어떻게 돌리지?"의 정답은 "안 돌린다"다. 별도 FastAPI 컨테이너로 분리하고 HTTP로 호출한다. Immich는 ONNX Runtime + FastAPI + ONNX 모델 자동 다운로드(huggingface-hub)로 완성형 ML 서비스를 보여준다. 모델 캐시까지 볼륨으로 분리된 점도 흥미롭다.

실습 아이디어: 자기 ML 모델을 ONNX로 export하고 FastAPI로 감싸 Docker로 띄워본다.

학습 포인트 6

Flutter로 자동 백업 백그라운드 작업 구현하기

"앱이 닫혀 있어도 알아서 사진을 백업한다"는 OS의 백그라운드 API 없이는 불가능하다. Immich 모바일의 android/(WorkManager)와 ios/(PhotoKit + BGTaskScheduler) 코드는 크로스플랫폼 백그라운드 작업의 정석 사례다. 배터리·네트워크 상태 감지, 충전 중일 때만 백업, 와이파이 전용 등 모든 디테일이 들어있다.

실습 아이디어: mobile/lib의 백업 모듈을 읽고, 자기 Flutter 앱에 "주기적 백그라운드 동기화" 기능을 붙여본다.

7하드웨어/시스템 요구사항

"내 NAS에서 돌릴 수 있나?" 답하는 가이드.

구성최소권장비고
CPU2 core (x86_64 또는 arm64)4 core+Raspberry Pi 5 가능
RAM4 GB6+ GBML 컨테이너만 2~3GB 먹음
저장소사진 양 + 30% (DB·캐시)SSD on DB / HDD on 사진DB_STORAGE_TYPE=HDD 옵션 있음
OSLinux/macOS/Windows(WSL2)Linux 권장Docker 가능한 모든 환경
Docker20.10+최신Docker Compose v2 필수
GPU (옵션)없음 (CPU 가능)NVIDIA / Intel iGPU / Apple Silicon얼굴 인식 속도 5~10배 향상
사용 예
시놀로지 DS920+ / DS923+ 같은 미드급 NAS

RAM 8~16GB 업그레이드만 하면 가족 3~4명이 쓰는 Immich 인스턴스를 충분히 돌린다. 시놀로지 NAS는 DSM에 Container Manager(구 Docker)가 내장돼 있어 GUI로 docker-compose 올릴 수 있다.

주의
데이터 백업은 필수 — 3-2-1 룰

README 첫 줄에 경고가 박혀 있다 — "Always follow 3-2-1 backup plan". 사본 3개, 매체 2종류, 원격 1곳. NAS 한 대에만 저장하다 디스크가 죽으면 평생 사진이 사라진다. Immich가 안정적이지만 백업의 책임은 사용자에게 있다.

실용적 조합 — 원본은 NAS(RAID), 매주 자동 외장하드 백업, 매월 클라우드(Backblaze B2 등)로 암호화 업로드.

하드웨어 가속 옵션(머신러닝)

NVIDIA GPU         → :release-cuda 태그   (CUDA 12 필요)
Intel iGPU         → :release-openvino    (OpenVINO 백엔드)
AMD GPU            → :release-rocm        (ROCm 6.x)
ARM SBC (Pi 등)    → :release-armnn       (ARM NN)
Rockchip NPU       → :release-rknn        (RK3588 등)

가속기 없어도 동작하지만 — CPU만으로 사진 1만 장 처리하면 며칠 걸린다. 가속 붙이면 몇 시간으로 줄어든다.

8직접 해볼 수 있는 실습 과제

난이도별로 5개 — 1번은 30분, 5번은 한 달짜리.

난이도 ★☆☆☆☆ — 30분

1. demo.immich.app에서 한 바퀴 돌기

설치 없이 공식 데모 서버에 로그인(demo@immich.app / demo)해서 검색·앨범·지도·얼굴 인식 UX를 직접 만져본다. "왜 이게 인기인가"를 손으로 체감하는 것이 첫 단계. 모바일 앱도 같은 서버로 붙여서 자동 백업까지 해본다.

난이도 ★★☆☆☆ — 1시간

2. 노트북에 Docker Compose로 셀프호스팅

공식 가이드대로 4컨테이너를 띄우고, 본인 폰의 사진 100장을 업로드해본다. UPLOAD_LOCATION 환경 변수가 어떻게 호스트 폴더로 마운트되는지, BullMQ 워커 로그가 어떻게 흘러가는지를 관찰. docker logs immich_server를 한참 들여다보는 시간이 가장 배움이 크다.

난이도 ★★★☆☆ — 1주

3. 검색 API 분석 → 자기 프로젝트에 시맨틱 서치 붙이기

server/src/queries/search.repository.sql.ts의 벡터 검색 SQL을 따라 읽는다. 그리고 자기 블로그/노트 컬렉션에 동일 패턴(PostgreSQL + pgvector + OpenAI 임베딩 API)을 적용해 "자연어 검색기"를 만든다. Immich가 풀어놓은 정답을 카피하는 게 합법인 분야다.

난이도 ★★★★☆ — 2주

4. Wasm 플러그인 작성하기

packages/plugin-sdk를 읽고 Extism 기반 플러그인을 하나 만든다. 예 — "사진 업로드 시 외부 webhook 호출하기", "AI로 사진 캡션 자동 생성하기". Rust나 Go로 짜서 Wasm으로 컴파일하고 Immich에 로드한다. Wasm 플러그인 시스템이 어떻게 격리되는지를 몸으로 익힌다.

난이도 ★★★★★ — 1달

5. CONTRIBUTING.md 따라 첫 PR 보내기

1만 개 커밋, 109개 dependent 프로젝트, 5.6k forks. 이 정도 규모 OSS에 PR 하는 경험은 그 자체로 자산이다. 시작점은 — good first issue 라벨, 번역 PR(Weblate), 또는 문서 오타 수정. 첫 PR이 머지되면 그다음부터는 코드도 손댄다.

9관련 기술 심화 학습 로드맵

Immich에서 영감 받아 진짜로 풀스택 엔지니어로 자라는 12주 계획.

Week 1~2 — 백엔드 기초

NestJS + TypeORM/Kysely 마스터

공식 튜토리얼로 "Cats CRUD"부터 시작 → Module/Controller/Service 분리 패턴 → Dependency Injection 원리 → Guard·Pipe·Interceptor → Swagger 자동 생성. Immich의 server/src/asset.module.ts를 끝에 다시 읽으면 모든 게 이해된다.

Week 3~4 — 비동기/큐 시스템

BullMQ + Redis로 워커 패턴 구현

이메일 보내기, 영상 트랜스코딩, AI 추론 같은 무거운 작업을 큐로 빼는 패턴. 우선순위·재시도·rate-limit·동시성 제어 — 모든 production 백엔드의 필수 기술이다. Immich의 workers/를 참고서로.

Week 5~6 — 프론트엔드 한 가지 깊이

SvelteKit + Svelte 5 Runes

"React만 알면 좁다"가 사실이다. Svelte는 React보다 코드가 30% 적고, 빌드 결과물도 작다. SvelteKit 공식 튜토리얼(learn.svelte.dev) → Immich 웹의 routes/를 따라가며 "실제 production 패턴" 학습. Svelte 5 Runes($state, $derived, $effect)도 같이.

Week 7~8 — Docker + DevOps

Docker Compose → 멀티 컨테이너 운영 → 모니터링

Immich docker-compose.yml을 한 줄씩 분해 → healthcheck·depends_on·volumes 이해. 그리고 OpenTelemetry로 분산 트레이싱 셋업(Immich가 이미 들어있다). Grafana + Loki + Tempo 스택으로 모니터링 대시보드까지.

Week 9~10 — 머신러닝 서빙

ONNX Runtime + FastAPI로 ML 마이크로서비스

Hugging Face에서 모델 받기 → ONNX export → FastAPI로 감싸기 → Docker 멀티 아키텍처 빌드(amd64+arm64). GPU 가속 옵션(CUDA/OpenVINO)까지 붙이면 Immich의 machine-learning/ 폴더와 거의 비슷한 결과물이 나온다.

Week 11~12 — 모바일까지 풀스택

Flutter로 자기 백엔드와 통신하는 앱 만들기

이미 만든 NestJS API에 Flutter 클라이언트를 붙인다. dio로 HTTP, provider/riverpod로 상태관리, image_picker + flutter_image_compress로 업로드. OpenAPI 생성기로 Dart 클라이언트 자동 생성까지 하면 Immich 수준의 풀스택 파이프라인.

10핵심 키워드 사전

레포 곳곳에 등장하는 용어 빠른 참조.

용어
AGPL-3.0 (Affero General Public License v3)
GPL의 강화판. "네트워크 너머로 서비스 제공할 때도 소스코드 공개 의무"가 추가된 라이선스. Immich를 fork해서 SaaS로 팔려면 변경사항을 사용자에게 공개해야 한다. Plausible, Grafana, Nextcloud 등 OSS-비즈니스 프로젝트가 자주 쓴다.
용어
CLIP (Contrastive Language-Image Pretraining)
OpenAI가 2021년 발표한 모델로, 사진과 텍스트를 같은 벡터 공간에 매핑한다. 결과 — "강아지 사진" 텍스트의 임베딩과 강아지 사진의 임베딩이 코사인 유사도 상 가깝다. Immich의 자연어 검색은 이걸로 동작한다.
용어
EXIF (Exchangeable Image File Format)
사진 파일에 박혀있는 메타데이터 — 촬영 일시·카메라 모델·렌즈·셔터 속도·ISO·GPS 좌표 등. exiftool이 사실상 모든 포맷에 대해 표준 도구. Immich는 exiftool-vendored로 EXIF를 뽑아 DB에 색인한다.
용어
FFmpeg (영상/오디오 처리 도구)
동영상 트랜스코딩의 사실상 표준. Immich는 업로드된 영상을 브라우저에서 재생 가능한 H.264 mp4로 변환한다. GPU 가속(nvenc, quicksync, vaapi 등) 옵션을 docker-compose의 hwaccel.transcoding.yml에서 켤 수 있다.
용어
InsightFace
중국 DeepInsight 팀이 만든 얼굴 인식 오픈소스. 얼굴 검출(SCRFD), 얼굴 임베딩(ArcFace 손실 함수), 나이/성별 추정 등을 모두 제공. Immich는 InsightFace로 얼굴을 검출하고 512차원 벡터로 임베딩한 뒤, Postgres에서 비슷한 벡터끼리 묶어 "같은 사람"으로 클러스터링한다.
용어
justified-layout (정렬된 갤러리 레이아웃)
Flickr가 2014년 만든 알고리즘 — 사진들의 가로/세로 비율을 보고 한 줄에 들어갈 사진 개수를 동적으로 결정해 모든 줄의 높이가 비슷해지도록 정렬. Google Photos도 같은 방식. Immich는 이걸 WebAssembly로 짠 @immich/justified-layout-wasm으로 가속한다.
용어
MapLibre GL JS
Mapbox가 2020년 라이선스를 바꾼 후 커뮤니티가 만든 OSS fork. WebGL 기반 인터랙티브 지도. Immich는 사진의 GPS 좌표를 모아 지도에 표시. pmtiles(단일 파일 타일 포맷)와 함께 쓰면 외부 의존성 없이 셀프호스팅 가능.
용어
pgvector / pgvecto.rs / VectorChord
PostgreSQL에 벡터 검색을 추가하는 확장 3종. pgvector(C, 표준) → pgvecto.rs(Rust, TensorChord 사) → VectorChord(차세대 IVF + RaBitQ 인덱스). Immich는 두 가지 확장이 동시 설치된 커스텀 Postgres 이미지를 만들어 마이그레이션 중.
용어
ONNX (Open Neural Network Exchange)
PyTorch/TensorFlow 모델을 표현하는 중립 포맷. ONNX Runtime이 그 포맷을 받아 CPU/GPU/NPU 어디서든 빠르게 실행. Immich가 5개 가속기를 지원할 수 있는 이유 — 모델을 모두 ONNX로 변환했기 때문.
용어
RapidOCR
PaddleOCR(중국 바이두의 OCR 엔진)의 경량 fork. 30+ 언어 텍스트 추출. Immich는 사진에서 텍스트(간판·표지판·문서)를 뽑아 검색 인덱스에 추가한다 — "영수증" 텍스트가 박힌 사진을 자연어로 찾을 수 있게.
용어
Sharp (libvips 기반 Node 이미지 처리)
Node.js 진영의 가장 빠른 이미지 처리 라이브러리. C로 짜인 libvips를 래핑. Jpeg/png/webp 변환, 리사이즈, 회전, 합성 등. ImageMagick보다 5~10배 빠르다. Immich의 모든 썸네일·프리뷰는 Sharp가 만든다.
용어
thumbhash
사진의 흐릿한 미리보기를 ~25바이트로 압축하는 포맷. 사진을 다운로드하기 전 placeholder로 보여줘 "사진이 천천히 뜨는 답답함"을 없앤다. Apple의 BlurHash 대안. Immich가 갤러리 스크롤 부드러움의 비결 중 하나.
용어
Valkey (Redis OSS fork)
2024년 Redis Inc.가 라이선스를 SSPL로 바꾸자 Linux Foundation 산하에서 갈라져 나온 진짜 OSS fork. AWS·Google이 후원. Immich는 docker-compose 기본값을 Redis → Valkey로 갈아탔다. 인터페이스는 100% 호환.
용어
FUTO
Eron Wolf(전 SpaceX 엔지니어)가 텍사스 오스틴에 세운 비영리 OSS 후원 재단. "Big Tech에 휘둘리지 않는 자유 소프트웨어"가 모토. Immich, GrayJay(유튜브 대안 앱) 등을 후원/직고용한다. Immich의 풀타임 메인테이너 Alex Tran은 FUTO 소속.

11참고 링크

더 깊이 파고들 때 봐야 할 1차 자료.

DEEP DIVE — TRY IT NOW

지금 당장 30분만 투자한다면?

  1. 데모 서버 접속demo.immich.app에 로그인해 검색창에 "선셋", "고양이", "도로" 같은 자연어 검색을 직접 해본다. CLIP의 위력을 손으로 체감.
  2. docker-compose.yml 정독 — 91줄짜리 파일을 한 줄씩 주석 달며 읽는다. 4 컨테이너 토폴로지가 머리에 박힌다.
  3. 아카이브하지 말고 진짜로 설치 — 노트북이나 Raspberry Pi에 띄워보고 자기 사진 100장 던져본다. 백엔드 로그가 큐를 흘리는 모습을 보는 게 진짜 학습이다.
  4. 한 PR — 한국어 번역 개선 — Weblate(hosted.weblate.org/projects/immich)에 가입 후 한국어 UI에서 어색한 문장 5개만 다듬어본다. 첫 OSS 기여 경험.
출처: GitHub immich-app/immich · 공식 사이트 immich.app · Trendshift repositories/1398 · 2026-05-23 기준 v2.7.5 · 분석: 2026-05-23