PhotoPrism is a privacy-focused photo and video manager for people who want a searchable library without handing their originals to a hosted platform. It combines a responsive web interface, local indexing, metadata extraction, labels, face recognition, maps, WebDAV, sharing, and an installable PWA.

This is not just a thumbnail viewer. PhotoPrism maintains a media index, generates derived files, processes video and RAW formats, and stores application state in a database. That makes it capable, but it also means the storage and backup design deserves more attention than a single-folder gallery.

What Is PhotoPrism?

Repository: https://github.com/photoprism/photoprism
Checked commit: 70e20b5 (2026-10-24)
License: AGPL-3.0
Primary language: Go
Frontend: Vue and JavaScript
Recommended database: MariaDB/MySQL
Media tooling: ExifTool, libvips, FFmpeg, RAW tooling, TensorFlow/ONNX components
Tested image: photoprism/photoprism:latest, digest-pinned

The main container indexes local originals and serves the UI. MariaDB stores the searchable index and application data. The originals directory remains the source media, while PhotoPrism’s storage directory contains thumbnails, cache data, sidecars, configuration, album backups, and database backups.

Features

  • search across filenames, dates, places, labels, people, colors, quality, resolution, and media properties;
  • local metadata extraction from EXIF, XMP, and related sources;
  • automatic labels, face detection, and face recognition;
  • RAW photos, common image types, videos, Live Photos, and generated previews;
  • maps and reverse-geocoding support for location-aware libraries;
  • WebDAV access for compatible desktop clients;
  • mobile upload workflows with compatible apps such as PhotoSync;
  • browser UI and installable PWA shell for phones and desktops;
  • sharing, albums, favorites, archive/review workflows, and user accounts;
  • optional Ollama vision workflows.

The local computer-vision features do not require sending your library to a cloud AI provider. Optional Ollama integration is a separate service and should be enabled only when you want its model workflow and have planned for model storage and RAM.

Self-Hosting with Docker

The reusable Home-Lab profile is available here:

Home-Lab PhotoPrism Compose
services:
  photoprism:
    image: ${PHOTOPRISM_IMAGE:-photoprism/photoprism@sha256:0f85369636ad99ca9a1c33f2d04df6c590802d16b7c33b4a1ea026b595be06d1}
    container_name: homelab-photoprism
    depends_on:
      mariadb:
        condition: service_healthy
    ports:
      - "${PHOTOPRISM_PORT:-3840}:2342"
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    environment:
      PHOTOPRISM_ADMIN_USER: "${PHOTOPRISM_ADMIN_USER:-admin}"
      PHOTOPRISM_ADMIN_PASSWORD: "${PHOTOPRISM_ADMIN_PASSWORD:?Set PHOTOPRISM_ADMIN_PASSWORD in .env}"
      PHOTOPRISM_AUTH_MODE: "password"
      PHOTOPRISM_SITE_URL: "${PHOTOPRISM_SITE_URL:-http://192.168.1.2:3840/}"
      PHOTOPRISM_SITE_TITLE: "PhotoPrism"
      PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
      PHOTOPRISM_DEFAULT_LOCALE: "en"
      PHOTOPRISM_PLACES_LOCALE: "local"
      PHOTOPRISM_LOG_LEVEL: "info"
      PHOTOPRISM_READONLY: "false"
      PHOTOPRISM_DISABLE_TLS: "true"
      PHOTOPRISM_DEFAULT_TLS: "false"
      PHOTOPRISM_DISABLE_CHOWN: "false"
      PHOTOPRISM_DISABLE_WEBDAV: "false"
      PHOTOPRISM_DISABLE_MCP: "false"
      PHOTOPRISM_DISABLE_SETTINGS: "false"
      PHOTOPRISM_DISABLE_PLACES: "false"
      PHOTOPRISM_DISABLE_EXIFTOOL: "false"
      PHOTOPRISM_DISABLE_TENSORFLOW: "false"
      PHOTOPRISM_DISABLE_FACES: "false"
      PHOTOPRISM_DISABLE_RAW: "false"
      PHOTOPRISM_SIDECAR_YAML: "true"
      PHOTOPRISM_BACKUP_ALBUMS: "true"
      PHOTOPRISM_BACKUP_DATABASE: "true"
      PHOTOPRISM_BACKUP_SCHEDULE: "daily"
      PHOTOPRISM_INDEX_SCHEDULE: ""
      PHOTOPRISM_AUTO_INDEX: "300"
      PHOTOPRISM_AUTO_IMPORT: "-1"
      PHOTOPRISM_UPLOAD_NSFW: "true"
      PHOTOPRISM_XMP_FACES: "true"
      PHOTOPRISM_UPLOAD_ARCHIVES: "true"
      PHOTOPRISM_UPLOAD_LIMIT: "5000"
      PHOTOPRISM_ORIGINALS_LIMIT: "5000"
      PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip"
      PHOTOPRISM_DATABASE_DRIVER: "mysql"
      PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
      PHOTOPRISM_DATABASE_NAME: "photoprism"
      PHOTOPRISM_DATABASE_USER: "photoprism"
      PHOTOPRISM_DATABASE_PASSWORD: "${MARIADB_PASSWORD:?Set MARIADB_PASSWORD in .env}"
      PHOTOPRISM_INIT: "update"
      PHOTOPRISM_UID: "1000"
      PHOTOPRISM_GID: "1000"
    volumes:
      - "${PHOTOPRISM_ORIGINALS_PATH:-./originals}:/photoprism/originals"
      - "${PHOTOPRISM_IMPORT_PATH:-./import}:/photoprism/import"
      - "${PHOTOPRISM_STORAGE_PATH:-./storage}:/photoprism/storage"
    restart: unless-stopped

  mariadb:
    image: ${MARIADB_IMAGE:-mariadb@sha256:99c125f103f5d081ebbc9ffe064e63daf7f688ac33a5f7f29af2d7260a96debf}
    container_name: homelab-photoprism-mariadb
    command: --innodb-buffer-pool-size=512M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
    environment:
      MARIADB_AUTO_UPGRADE: "1"
      MARIADB_INITDB_SKIP_TZINFO: "1"
      MARIADB_DATABASE: "photoprism"
      MARIADB_USER: "photoprism"
      MARIADB_PASSWORD: "${MARIADB_PASSWORD:?Set MARIADB_PASSWORD in .env}"
      MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD:?Set MARIADB_ROOT_PASSWORD in .env}"
    volumes:
      - photoprism_database:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 12
    restart: unless-stopped

volumes:
  photoprism_database:
    name: homelab_photoprism_database

Start it:

cd /home/jalcocert/Desktop/Home-Lab/photoprism
cp .env.sample .env
# Replace the three password values in .env.
mkdir -p originals import storage
docker compose pull
docker compose up -d
docker compose ps

The tested LAN UI is:

http://192.168.1.2:3840

The admin username is admin by default and the password is the value you set in PHOTOPRISM_ADMIN_PASSWORD. There is no universal default password. The profile uses MariaDB internally and does not publish the database port to the host.

Put photos and videos in originals/, or set PHOTOPRISM_ORIGINALS_PATH to an existing library. Use import/ for files PhotoPrism should process into the managed originals library. The storage/ directory and MariaDB volume must be persisted.

Field Note: The Empty Library Started Successfully

I tested the digest-pinned PhotoPrism and MariaDB images with empty originals and import directories. MariaDB became healthy first. PhotoPrism then completed its startup migrations, initialized its runtime packages, and listened on port 2342 inside the container.

The host-level checks were:

curl -fsS http://127.0.0.1:3840/api/v1/status
# {"status":"operational"}

curl -fsS -D - http://127.0.0.1:3840/ -o /dev/null
# HTTP/1.1 307 Temporary Redirect
# Location: /library/login

The first startup took longer than a typical web-only container because the image ran its configured package initialization and database migrations. This trial validates the empty-library deployment path; it does not benchmark indexing, face recognition, GPU acceleration, or a large media import.

Originals, Storage and Backups

The most important PhotoPrism distinction is between originals and generated state:

Location What it contains Backup importance
originals/ Source photos and videos The irreplaceable media
import/ Optional staging files Back up if it contains files not yet imported
storage/ Thumbnails, cache, sidecars, config, album/database backups Needed for a complete, convenient restore
MariaDB volume Search index, users, albums, metadata and application state Required to preserve the library database

Do not rely on the database alone. Do not assume the originals directory alone recreates your labels, faces, albums, users, and settings. Back up all components, and test a restore on a separate instance before changing the production library.

PhotoPrism can write YAML sidecars and album backups, which helps make metadata more portable, but these are complementary to a complete backup rather than a substitute for one.

PWA, WebDAV and Remote Access

PhotoPrism’s browser client can be installed as a PWA, which gives a phone or desktop an app-like launcher and responsive UI. It is not a full offline-first photo application. Search, permissions, indexes, thumbnails, and most library operations still depend on the PhotoPrism server.

WebDAV is useful for desktop file workflows and compatible mobile backup tools, but it should be protected with HTTPS and carefully scoped credentials. It is an access path into the library, not a backup system.

The Home-Lab profile uses HTTP only for trusted-LAN testing. For remote use, put PhotoPrism behind a reverse proxy with HTTPS, set PHOTOPRISM_SITE_URL to that public URL, and review upload, WebDAV, sharing, and account settings before opening it to the internet.

Database, AI and Hardware

MariaDB is the recommended database for larger or multi-user libraries. SQLite is simpler and can suit smaller installations, but MariaDB gives the index more room for concurrent activity. Redis is not required for the standard stack, and the database is not exposed publicly in the Home-Lab Compose.

CPU processing is the portable default. Larger libraries benefit from fast storage, adequate RAM and swap, and possibly Intel, NVIDIA, Apple, or Raspberry Pi acceleration. GPU setup is platform-specific and should be added only after the CPU deployment works.

PhotoPrism includes local vision components for labels and faces. Optional Ollama integration is a separate model runner, not a mandatory dependency. It can add semantic or generative workflows, but it also brings model downloads, hardware requirements, and another container to secure.

Compared with Other Photo Projects

Project Best fit Difference from PhotoPrism
Immich Phone-first backup, sharing, and modern photo UX PhotoPrism emphasizes mature indexing, metadata, WebDAV, and broad file handling
Ente End-to-end encrypted photo workflows PhotoPrism keeps processing and the primary library on your server; it is not an E2EE-by-default archive
Photoview Lightweight self-hosted gallery PhotoPrism adds deeper search, labels, faces, maps, WebDAV, and media processing
PhotoStream or simple galleries Browse a directory PhotoPrism builds a searchable media index with accounts and metadata

FAQ

Conclusion

PhotoPrism is a strong choice when you want a private, searchable photo archive with local processing and a broad file-oriented workflow. It is more involved than a simple gallery because it maintains a database-backed index, generated thumbnails, sidecars, faces, labels, maps, WebDAV, and backups.

Start with the tested two-container LAN profile, create your own admin password, add a small disposable library, and verify backup/restore before importing everything. Once the fundamentals are reliable, add HTTPS, GPU acceleration, WebDAV, PWA access, or Ollama deliberately.