Siftr

Siftr

Docker app from Daneng66's Repository

Overview

Siftr is a self-hosted photo manager that helps you sift through your library with smart renaming, organizing, and deduplication. Exact and perceptual duplicate detection is powered by czkawka, and EXIF write-back uses exiftool—both bundled in the image, nothing else to install. Point the /data volume at where your photos live and open the web UI.

Siftr

Sift through your photo library with smart renaming, browsing, and deduplication.

Siftr is a self-hosted photo manager that ships as a single all-in-one Docker container — React frontend, Node/Express API, SQLite index, and the czkawka_cli deduplication engine all bundled and served from one port.

Features

  • Library browser — fast, virtualized photo grid that stays smooth at 1,000–10,000 photos. Hover quick-actions (download / select) and corner badges (duplicate indicator, file size).
  • Deduplicationczkawka_cli finds exact (hash-based) duplicate groups. Compare copies side-by-side and pick which to keep; deletions move to a .trash you can restore from or empty at any time. (A perceptual "similar images" pass is also wired up, behind DEDUP_SIMILAR=true; off by default for now.)
  • Bulk rename — pattern tokens ({date:…}, {seq:N}, {original}, {camera}, {custom}) with a live preview and collision detection.
  • Metadata editing — view and edit EXIF (date, GPS, camera) individually or across a selection; changes are written back into the files with exiftool.
  • Folders — the sidebar mirrors the actual directory structure of your photos on disk; pick a folder to browse just the photos it contains.
  • UX — card dashboard, left sidebar (folders / filters / stats), top nav, dark mode, and low-friction bulk selection (click, shift-click range, ctrl-click toggle, drag-select marquee).

Quick start (Docker)

docker build -t siftr .
docker run -p 8080:8080 -v ./data:/data siftr

Then open http://localhost:8080.

Put your photos under the mounted volume at ./data/photos (sub-folders are scanned recursively) and click Scan. All persistent data lives under the one volume:

data/
  photos/       # your images (the watched library — source of truth)
  thumbnails/   # generated WebP thumbnails
  db/siftr.sqlite
  .trash/       # files removed via "Move to trash" (restore or empty from the UI)

Install on unraid

Siftr ships as an unraid template (unraid/siftr.xml) backed by the prebuilt GHCR image ghcr.io/daneng66/siftr. Until it lands in Community Apps, add it manually:

  1. Docker → Add Container, then in Template repositories (under Docker settings) add https://github.com/Daneng66/Siftr and Save.

  2. Back on Add Container, select the Siftr template.

  3. Set the port and path mappings, then apply. Each row below maps a value on your unraid host to a fixed location inside the container — only the Host value is yours to choose; leave the Container value as shown.

    Port (Config Type: Port)

    Name Container port Host port Notes
    WebUI Port 8080 8080 TCP. Change the host port only if 8080 is already taken.

    Paths (Config Type: Path)

    Name Container path Host path (example) Access mode Notes
    App Data /data /mnt/user/appdata/siftr Read/Write Database, thumbnails, and .trash. Keep on a fast cache/appdata share.
    Photo Library /data/photos /mnt/user/Photos Read/Write Your existing photo share. Must be writable so Siftr can rename files and write EXIF. The container path is intentionally nested under /data, but its host path can live on a separate (e.g. array) share.
    Trash Folder (advanced, optional) /data/.trash /mnt/user/appdata/siftr/.trash Read/Write Where "Move to trash" relocates removed files. Defaults inside App Data; map to its own host share to keep trashed files off appdata or recover them elsewhere.
  4. Open the WebUI on the host port from above (default 8080) and click Scan.

Advanced options (similar-image dedup, scan concurrency, thumbnail size, etc.) are exposed as template variables; see Configuration.

[!NOTE] The image is linux/amd64 only — czkawka has no ARM build — so Siftr targets standard Intel/AMD unraid hardware.

Architecture

A single Node.js process serves the API under /api/* and the built React SPA for everything else.

  • Backend: Express + TypeScript, better-sqlite3 (in-process, no DB daemon), sharp (thumbnails/dimensions), exifr (EXIF read), exiftool (EXIF write), czkawka_cli (dedup) via child process. An in-process job queue runs scans and dedup with progress exposed at /api/jobs.
  • Frontend: React + Vite + Tailwind, TanStack Query (server state), Zustand (selection/UI), @tanstack/react-virtual (grid virtualization).
server/   Express API, scanner, dedup, exif, db
client/   React app
Dockerfile  multi-stage build (client + server -> slim runtime)

Local development

Requires Node 20 or 22 LTS (native modules better-sqlite3/sharp ship prebuilt binaries for LTS releases). exiftool and czkawka_cli must be on PATH for metadata-write and dedup features (or point EXIFTOOL_BIN / CZKAWKA_BIN at them); everything else runs without them.

npm install
npm run dev        # Express on :8080, Vite dev server on :5173 (proxies /api)
# or, production-style:
npm run build && DATA_DIR=./data npm start

Run the backend unit tests (rename pattern engine + czkawka output parser):

npm test

Configuration (environment variables)

Var Default Purpose
PORT 8080 HTTP port
DATA_DIR /data Root of the persisted volume
TRASH_DIR $DATA_DIR/.trash Holding area for "Move to trash" deletions; point at a separate path/share to keep trashed files off the data volume
SCAN_ON_STARTUP true Scan the library on boot
SCAN_CONCURRENCY 4 Parallel hash/thumbnail workers
THUMB_SIZE 256 Thumbnail max dimension (px)
DEDUP_SIMILAR false Also run czkawka's perceptual near-duplicate pass
CZKAWKA_IMAGE_PRESET High Similarity sensitivity (MinimalVeryHigh) for the perceptual pass
CZKAWKA_BIN czkawka_cli Path to the dedup binary
EXIFTOOL_BIN exiftool Path to exiftool

Notes

  • czkawka_cli flag/output formats vary across versions; the parser is tolerant of both duplicate and similar-image result files. The Docker image pins a version via the CZKAWKA_VERSION build arg.
  • Metadata edits are written in place with -overwrite_original. Keep backups of irreplaceable originals.

Install Siftr on Unraid in a few clicks.

Find Siftr in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for Siftr Review the template variables and paths Click Install

Related apps

Details

Repository
ghcr.io/daneng66/siftr:latest
Last Updated2026-07-01
First Seen2026-06-22

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
sh
Privileged
false

Template configuration

WebUI PortPorttcp

Port the Siftr web interface is served on.

Target
8080
Default
8080
Value
8080
App DataPathrw

Working data: the SQLite database, generated thumbnails, and the .trash holding area for removed duplicates. Keep this on a fast share (e.g. cache/appdata).

Target
/data
Default
/mnt/user/appdata/siftr
Value
/mnt/user/appdata/siftr
Photo LibraryPathrw

Your photo library. Siftr reads, renames, organizes and writes EXIF here, so it must be read/write. Mapped inside /data so it can live on a large array share separate from App Data.

Target
/data/photos
Default
/mnt/user/Photos
Value
/mnt/user/Photos
Trash FolderPathrw

Holding area for duplicates removed via 'Move to trash' (reversible deletion). By default it lives inside App Data; map it to a separate share to keep trashed files off your appdata or to recover them elsewhere.

Target
/data/.trash
Default
/mnt/user/appdata/siftr/.trash
Value
/mnt/user/appdata/siftr/.trash
Enable Similar-Image DedupVariable

Also run czkawka's perceptual (near-duplicate) image pass in addition to exact hash matching. Slower. Set to true to enable.

Target
DEDUP_SIMILAR
Default
false
Value
false
Similar-Image PresetVariable

czkawka similarity sensitivity for the perceptual pass: Minimal, VeryLow, Low, Medium, High, or VeryHigh. Only used when similar-image dedup is enabled.

Target
CZKAWKA_IMAGE_PRESET
Default
High
Value
High
Scan On StartupVariable

Scan the photo library for new/changed files when the container starts. Set to false to only scan on demand.

Target
SCAN_ON_STARTUP
Default
true
Value
true
Scan ConcurrencyVariable

How many photos to hash and thumbnail in parallel during a scan. Raise on powerful CPUs, lower to reduce load.

Target
SCAN_CONCURRENCY
Default
4
Value
4
Thumbnail SizeVariable

Edge length in pixels of generated grid thumbnails.

Target
THUMB_SIZE
Default
256
Value
256